focus-data-toolkit 0.12.0__tar.gz → 0.13.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.
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/CHANGELOG.md +23 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/CONTRIBUTING.md +9 -1
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/MANIFEST.in +2 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/NOTICE +11 -0
- focus_data_toolkit-0.13.0/PKG-INFO +157 -0
- focus_data_toolkit-0.13.0/README.md +104 -0
- focus_data_toolkit-0.13.0/docs/generator-corrections.md +198 -0
- focus_data_toolkit-0.13.0/docs/generator-statistics.json +77 -0
- focus_data_toolkit-0.13.0/docs/pr53-review-followup.md +61 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/docs/versioning.md +8 -2
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/pyproject.toml +3 -0
- focus_data_toolkit-0.13.0/scripts/__init__.py +1 -0
- focus_data_toolkit-0.13.0/scripts/describe_generated_samples.py +42 -0
- focus_data_toolkit-0.13.0/scripts/sample_audit.py +162 -0
- focus_data_toolkit-0.13.0/scripts/validate_official_samples.py +354 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/_version.py +1 -1
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/cli.py +17 -3
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/convert/invoice_detail.py +4 -1
- focus_data_toolkit-0.13.0/src/focus_data_toolkit/generators/engine/context.py +36 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/generators/engine/determinism.py +35 -21
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/generators/engine/json_focus.py +11 -10
- focus_data_toolkit-0.13.0/src/focus_data_toolkit/generators/engine/ladder.py +86 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/generators/engine/scenarios_core.py +68 -53
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/generators/engine/serialize.py +67 -50
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/generators/providers/aws.py +6 -9
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/generators/providers/azure.py +1 -6
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/generators/providers/gcp.py +0 -5
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/generators/providers/profile.py +2 -2
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/generators/versions/v1_3.py +9 -25
- focus_data_toolkit-0.13.0/src/focus_data_toolkit/model/focus_1_4_decimal_scale.json +49 -0
- focus_data_toolkit-0.13.0/src/focus_data_toolkit/official_report.py +66 -0
- focus_data_toolkit-0.13.0/src/focus_data_toolkit/official_validator.py +117 -0
- focus_data_toolkit-0.13.0/src/focus_data_toolkit.egg-info/PKG-INFO +157 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit.egg-info/SOURCES.txt +32 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/fixtures/golden/README.md +8 -2
- focus_data_toolkit-0.13.0/tests/fixtures/golden/compatibility_golden/aws_1_2_cost_and_usage_rows100_seed42.csv +101 -0
- focus_data_toolkit-0.13.0/tests/fixtures/golden/compatibility_golden/aws_1_2_cost_and_usage_rows25_seed7.csv +26 -0
- focus_data_toolkit-0.13.0/tests/fixtures/golden/compatibility_golden/aws_1_2_cost_and_usage_rows25_seed7_credits.csv +26 -0
- focus_data_toolkit-0.13.0/tests/fixtures/golden/compatibility_golden/aws_1_3_contract_commitment_rows100_seed42.csv +12 -0
- focus_data_toolkit-0.13.0/tests/fixtures/golden/compatibility_golden/aws_1_3_cost_and_usage_rows100_seed42.csv +101 -0
- focus_data_toolkit-0.13.0/tests/fixtures/golden/compatibility_golden/aws_1_3_cost_and_usage_rows25_seed7.csv +26 -0
- focus_data_toolkit-0.13.0/tests/fixtures/golden/compatibility_golden/aws_1_3_cost_and_usage_rows25_seed7_credits.csv +26 -0
- focus_data_toolkit-0.13.0/tests/fixtures/golden/compatibility_golden/azure_1_2_cost_and_usage_rows100_seed42.csv +101 -0
- focus_data_toolkit-0.13.0/tests/fixtures/golden/compatibility_golden/azure_1_2_cost_and_usage_rows25_seed7.csv +26 -0
- focus_data_toolkit-0.13.0/tests/fixtures/golden/compatibility_golden/azure_1_2_cost_and_usage_rows25_seed7_credits.csv +26 -0
- focus_data_toolkit-0.13.0/tests/fixtures/golden/compatibility_golden/azure_1_3_contract_commitment_rows100_seed42.csv +10 -0
- focus_data_toolkit-0.13.0/tests/fixtures/golden/compatibility_golden/azure_1_3_cost_and_usage_rows100_seed42.csv +101 -0
- focus_data_toolkit-0.13.0/tests/fixtures/golden/compatibility_golden/azure_1_3_cost_and_usage_rows25_seed7.csv +26 -0
- focus_data_toolkit-0.13.0/tests/fixtures/golden/compatibility_golden/azure_1_3_cost_and_usage_rows25_seed7_credits.csv +26 -0
- focus_data_toolkit-0.13.0/tests/fixtures/golden/compatibility_golden/gcp_1_2_cost_and_usage_rows100_seed42.csv +101 -0
- focus_data_toolkit-0.13.0/tests/fixtures/golden/compatibility_golden/gcp_1_2_cost_and_usage_rows25_seed7.csv +26 -0
- focus_data_toolkit-0.13.0/tests/fixtures/golden/compatibility_golden/gcp_1_2_cost_and_usage_rows25_seed7_credits.csv +26 -0
- focus_data_toolkit-0.13.0/tests/fixtures/golden/compatibility_golden/gcp_1_3_contract_commitment_rows100_seed42.csv +12 -0
- focus_data_toolkit-0.13.0/tests/fixtures/golden/compatibility_golden/gcp_1_3_cost_and_usage_rows100_seed42.csv +101 -0
- focus_data_toolkit-0.13.0/tests/fixtures/golden/compatibility_golden/gcp_1_3_cost_and_usage_rows25_seed7.csv +26 -0
- focus_data_toolkit-0.13.0/tests/fixtures/golden/compatibility_golden/gcp_1_3_cost_and_usage_rows25_seed7_credits.csv +26 -0
- focus_data_toolkit-0.13.0/tests/fixtures/golden/correctness_migration/README.md +10 -0
- focus_data_toolkit-0.13.0/tests/fixtures/golden/correctness_migration/pr67_before.json +815 -0
- focus_data_toolkit-0.13.0/tests/fixtures/official/generator_validation/README.md +15 -0
- focus_data_toolkit-0.13.0/tests/fixtures/official/generator_validation/aws_1.2_CostAndUsage.log +625 -0
- focus_data_toolkit-0.13.0/tests/fixtures/official/generator_validation/aws_1.2_CostAndUsage.stderr.log +0 -0
- focus_data_toolkit-0.13.0/tests/fixtures/official/generator_validation/aws_1.3_ContractCommitment.log +117 -0
- focus_data_toolkit-0.13.0/tests/fixtures/official/generator_validation/aws_1.3_ContractCommitment.stderr.log +0 -0
- focus_data_toolkit-0.13.0/tests/fixtures/official/generator_validation/aws_1.3_CostAndUsage.log +865 -0
- focus_data_toolkit-0.13.0/tests/fixtures/official/generator_validation/aws_1.3_CostAndUsage.stderr.log +0 -0
- focus_data_toolkit-0.13.0/tests/fixtures/official/generator_validation/azure_1.2_CostAndUsage.log +617 -0
- focus_data_toolkit-0.13.0/tests/fixtures/official/generator_validation/azure_1.2_CostAndUsage.stderr.log +0 -0
- focus_data_toolkit-0.13.0/tests/fixtures/official/generator_validation/azure_1.3_ContractCommitment.log +117 -0
- focus_data_toolkit-0.13.0/tests/fixtures/official/generator_validation/azure_1.3_ContractCommitment.stderr.log +0 -0
- focus_data_toolkit-0.13.0/tests/fixtures/official/generator_validation/azure_1.3_CostAndUsage.log +857 -0
- focus_data_toolkit-0.13.0/tests/fixtures/official/generator_validation/azure_1.3_CostAndUsage.stderr.log +0 -0
- focus_data_toolkit-0.13.0/tests/fixtures/official/generator_validation/baseline.json +35853 -0
- focus_data_toolkit-0.13.0/tests/fixtures/official/generator_validation/gcp_1.2_CostAndUsage.log +617 -0
- focus_data_toolkit-0.13.0/tests/fixtures/official/generator_validation/gcp_1.2_CostAndUsage.stderr.log +0 -0
- focus_data_toolkit-0.13.0/tests/fixtures/official/generator_validation/gcp_1.3_ContractCommitment.log +117 -0
- focus_data_toolkit-0.13.0/tests/fixtures/official/generator_validation/gcp_1.3_ContractCommitment.stderr.log +0 -0
- focus_data_toolkit-0.13.0/tests/fixtures/official/generator_validation/gcp_1.3_CostAndUsage.log +857 -0
- focus_data_toolkit-0.13.0/tests/fixtures/official/generator_validation/gcp_1.3_CostAndUsage.stderr.log +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_convert_roundtrip.py +1 -1
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_cross_provider.py +2 -2
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_fake_provider.py +0 -1
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_generated_conformance.py +35 -17
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_generators.py +3 -1
- focus_data_toolkit-0.13.0/tests/test_official_report.py +146 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_official_validator.py +2 -2
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_parquet.py +3 -3
- focus_data_toolkit-0.13.0/tests/test_reviewed_roundtrip.py +78 -0
- focus_data_toolkit-0.13.0/tests/test_reviewed_sample_semantics.py +150 -0
- focus_data_toolkit-0.12.0/PKG-INFO +0 -196
- focus_data_toolkit-0.12.0/README.md +0 -143
- focus_data_toolkit-0.12.0/scripts/validate_official_samples.py +0 -353
- focus_data_toolkit-0.12.0/src/focus_data_toolkit/generators/engine/context.py +0 -12
- focus_data_toolkit-0.12.0/src/focus_data_toolkit/generators/engine/ladder.py +0 -71
- focus_data_toolkit-0.12.0/src/focus_data_toolkit/model/focus_1_4_decimal_scale.json +0 -10
- focus_data_toolkit-0.12.0/src/focus_data_toolkit/official_validator.py +0 -61
- focus_data_toolkit-0.12.0/src/focus_data_toolkit.egg-info/PKG-INFO +0 -196
- focus_data_toolkit-0.12.0/tests/fixtures/golden/compatibility_golden/aws_1_2_cost_and_usage_rows100_seed42.csv +0 -101
- focus_data_toolkit-0.12.0/tests/fixtures/golden/compatibility_golden/aws_1_2_cost_and_usage_rows25_seed7.csv +0 -26
- focus_data_toolkit-0.12.0/tests/fixtures/golden/compatibility_golden/aws_1_2_cost_and_usage_rows25_seed7_credits.csv +0 -26
- focus_data_toolkit-0.12.0/tests/fixtures/golden/compatibility_golden/aws_1_3_contract_commitment_rows100_seed42.csv +0 -11
- focus_data_toolkit-0.12.0/tests/fixtures/golden/compatibility_golden/aws_1_3_cost_and_usage_rows100_seed42.csv +0 -101
- focus_data_toolkit-0.12.0/tests/fixtures/golden/compatibility_golden/aws_1_3_cost_and_usage_rows25_seed7.csv +0 -26
- focus_data_toolkit-0.12.0/tests/fixtures/golden/compatibility_golden/aws_1_3_cost_and_usage_rows25_seed7_credits.csv +0 -26
- focus_data_toolkit-0.12.0/tests/fixtures/golden/compatibility_golden/azure_1_2_cost_and_usage_rows100_seed42.csv +0 -101
- focus_data_toolkit-0.12.0/tests/fixtures/golden/compatibility_golden/azure_1_2_cost_and_usage_rows25_seed7.csv +0 -26
- focus_data_toolkit-0.12.0/tests/fixtures/golden/compatibility_golden/azure_1_2_cost_and_usage_rows25_seed7_credits.csv +0 -26
- focus_data_toolkit-0.12.0/tests/fixtures/golden/compatibility_golden/azure_1_3_contract_commitment_rows100_seed42.csv +0 -11
- focus_data_toolkit-0.12.0/tests/fixtures/golden/compatibility_golden/azure_1_3_cost_and_usage_rows100_seed42.csv +0 -101
- focus_data_toolkit-0.12.0/tests/fixtures/golden/compatibility_golden/azure_1_3_cost_and_usage_rows25_seed7.csv +0 -26
- focus_data_toolkit-0.12.0/tests/fixtures/golden/compatibility_golden/azure_1_3_cost_and_usage_rows25_seed7_credits.csv +0 -26
- focus_data_toolkit-0.12.0/tests/fixtures/golden/compatibility_golden/gcp_1_2_cost_and_usage_rows100_seed42.csv +0 -101
- focus_data_toolkit-0.12.0/tests/fixtures/golden/compatibility_golden/gcp_1_2_cost_and_usage_rows25_seed7.csv +0 -26
- focus_data_toolkit-0.12.0/tests/fixtures/golden/compatibility_golden/gcp_1_2_cost_and_usage_rows25_seed7_credits.csv +0 -26
- focus_data_toolkit-0.12.0/tests/fixtures/golden/compatibility_golden/gcp_1_3_contract_commitment_rows100_seed42.csv +0 -12
- focus_data_toolkit-0.12.0/tests/fixtures/golden/compatibility_golden/gcp_1_3_cost_and_usage_rows100_seed42.csv +0 -101
- focus_data_toolkit-0.12.0/tests/fixtures/golden/compatibility_golden/gcp_1_3_cost_and_usage_rows25_seed7.csv +0 -26
- focus_data_toolkit-0.12.0/tests/fixtures/golden/compatibility_golden/gcp_1_3_cost_and_usage_rows25_seed7_credits.csv +0 -26
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/LICENSE +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/LICENSES/CC-BY-4.0.txt +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/SECURITY.md +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/docs/audit/2026-07-improvement-plan.md +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/docs/audit/2026-07-repo-audit.md +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/docs/compatibility.md +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/docs/model-provenance.md +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/docs/releasing.md +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/docs/runner.md +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/docs/security-model.md +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/docs/studio.md +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/docs/supplements.md +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/schema/model_provenance.schema.json +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/scripts/check_pinned_actions.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/scripts/generate_resolved_sbom.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/scripts/generate_sbom.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/scripts/regenerate_golden_fixtures.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/scripts/verify_model_provenance.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/scripts/verify_release.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/setup.cfg +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/__init__.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/__main__.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/context/__init__.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/context/billing.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/context/provider.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/convert/__init__.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/convert/billing_period.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/convert/contract_applied.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/convert/contract_commitment.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/convert/cost_and_usage.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/convert/detect.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/convert/streaming.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/errors.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/focus_json.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/generators/__init__.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/generators/_shim.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/generators/engine/__init__.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/generators/engine/allocation_math.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/generators/generate_aws_focus_1_2.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/generators/generate_aws_focus_1_3.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/generators/generate_azure_focus_1_2.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/generators/generate_azure_focus_1_3.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/generators/generate_gcp_focus_1_2.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/generators/generate_gcp_focus_1_3.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/generators/providers/__init__.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/generators/scenarios.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/generators/versions/__init__.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/generators/versions/adapter.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/generators/versions/v1_2.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/io/__init__.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/io/atomic_writer.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/io/csv_io.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/io/parquet_io.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/io/records.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/io/row_source.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/lifecycle.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/manifest.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/model/__init__.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/model/capabilities.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/model/focus_1_4_model.json +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/model/focus_1_4_servicesubcategory.json +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/model/focus_json_keys.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/model/iso_4217_currencies.json +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/model/json_schema_check.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/model/json_schemas/allocatedmethoddetailsobjectschema.json +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/model/json_schemas/commitmentprogrameligibilitydetailsobjectschema.json +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/model/json_schemas/contractappliedobjectschema.json +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/model/json_schemas/contractcommitmentapplicabilityobjectschema.json +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/model/json_schemas/json_schemas_provenance.json +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/model/model_provenance.json +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/model/validator.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/modes.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/progress.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/provenance.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/py.typed +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/runtime.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/schema/__init__.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/schema/detection.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/schema/registry.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/storage/__init__.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/storage/external_index.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/storage/spill.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/studio/__init__.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/studio/app.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/studio/config.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/studio/frontend/app.js +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/studio/frontend/index.html +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/studio/frontend/style.css +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/studio/jobs.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/studio/preview.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/studio/security.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/studio/server.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/supplement/__init__.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/supplement/adapters/__init__.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/supplement/adapters/adapters_provenance.json +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/supplement/adapters/aws_invoice_summary.json +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/supplement/adapters/aws_savings_plans.json +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/supplement/adapters/azure_invoice.json +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/supplement/adapters/gcp_compute_commitments.json +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/supplement/adapters/registry.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/supplement/apply.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/supplement/gaps.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/supplement/kinds.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/supplement/loader.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/supplement/spec.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/supplement/validate.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/validate/__init__.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/validate/allocation.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/validate/bundle.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/validate/codes.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/validate/corrections.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/validate/reconciliation.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/validate/referential.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit.egg-info/dependency_links.txt +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit.egg-info/entry_points.txt +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit.egg-info/requires.txt +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit.egg-info/top_level.txt +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/conftest.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/fixtures/client_like/SOURCES.md +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/fixtures/client_like/consolidated_multi_provider_1_3.csv +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/fixtures/golden/compatibility_golden/scenarios_correction_set.csv +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/fixtures/golden/compatibility_golden/scenarios_sca_equal.csv +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/fixtures/golden/compatibility_golden/scenarios_sca_negative.csv +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/fixtures/golden/compatibility_golden/scenarios_sca_weighted.csv +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/fixtures/official/SOURCES.md +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/fixtures/official/invoice_detail_grain_example.json +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/fixtures/official/numeric_format_examples.json +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_adapters_aws.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_adapters_azure_gcp.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_atomic_write.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_billing_lifecycle.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_bundle_gate.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_bundle_validation.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_capabilities.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_cli.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_client_like.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_container.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_contract_applied.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_contract_commitment_semantics.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_corrections.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_detect.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_fixtures_are_synthetic.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_focus_json.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_gaps.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_generator_golden.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_grouping_keys.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_lifecycle_chains.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_lineage_counters.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_lint_focus.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_manifest.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_model_provenance.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_multi_provider.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_official_json_schemas.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_packaging.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_parquet_input.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_participant_entities.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_partitioning.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_progress_cancel.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_release_tooling.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_replace_recovery.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_runtime.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_schema_detection.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_single_source_focus_rules.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_spill.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_split_allocation.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_streaming.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_strict_conversion.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_studio.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_supplement_apply.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_supplement_loader.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_supplement_streaming.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_synthetic_conversion.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_validator.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_workflow_pins.py +0 -0
- {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tools/extract_focus_1_4_model.py +0 -0
|
@@ -9,6 +9,28 @@ policy.
|
|
|
9
9
|
|
|
10
10
|
## [Unreleased]
|
|
11
11
|
|
|
12
|
+
## [0.13.0] — 2026-09-05
|
|
13
|
+
|
|
14
|
+
Prepared in source; publishing is a separate release step.
|
|
15
|
+
|
|
16
|
+
- Correct period-subscription effective costs and derive illustrative 10% taxes
|
|
17
|
+
from earlier untaxed usage with exact amount and currency lineage.
|
|
18
|
+
- Stabilize offer/SKU/price identities and public prices; correct recognized storage
|
|
19
|
+
properties, AWS namespaces and owning subaccounts, including allocations.
|
|
20
|
+
- Model partially used fleets of 500 machines, exact annual capacity and complete
|
|
21
|
+
budget-aware groups. Add targeted 1.3 negotiated contracts, shared contract parents
|
|
22
|
+
and a common generation registry; Contract Commitment APIs accept `include_credits`.
|
|
23
|
+
- Omit inapplicable ContractApplied metric properties while retaining legacy input
|
|
24
|
+
compatibility. Preserve exact invoice aggregates and widen affected Parquet cost
|
|
25
|
+
columns to `decimal128(38,17)` without silent rounding.
|
|
26
|
+
- Replace FAIL-only official gating with complete inventories, violation counts,
|
|
27
|
+
resource/source/data fingerprints, archived reports and separately reviewed
|
|
28
|
+
candidate evidence. Public `validate --official` now rejects false-green exits.
|
|
29
|
+
- **New byte baseline:** regenerated provider goldens, archived before examples,
|
|
30
|
+
independent corruption tests and reproducible statistics. See
|
|
31
|
+
[generator corrections](docs/generator-corrections.md) for assumptions, residual
|
|
32
|
+
official failures and the deliberate differences from upstream PRs 6 and 7.
|
|
33
|
+
|
|
12
34
|
## [0.12.0] — 2026-08-21
|
|
13
35
|
|
|
14
36
|
Back-ports the reviewed FOCUS-Sample-Data conformance fixes into the generator engine.
|
|
@@ -695,6 +717,7 @@ conformance defects.
|
|
|
695
717
|
<!-- Reference links. 0.2.0/0.3.0 were pre-release development milestones and were never tagged
|
|
696
718
|
or published, so only the first public release (0.9.0) has a tag link. -->
|
|
697
719
|
[Unreleased]: https://github.com/guymano/focus-data-toolkit/compare/v0.12.0...HEAD
|
|
720
|
+
[0.13.0]: https://github.com/guymano/focus-data-toolkit/compare/v0.12.0...v0.13.0
|
|
698
721
|
[0.12.0]: https://github.com/guymano/focus-data-toolkit/compare/v0.11.0...v0.12.0
|
|
699
722
|
[0.11.0]: https://github.com/guymano/focus-data-toolkit/compare/v0.11.0rc1...v0.11.0
|
|
700
723
|
[0.11.0rc1]: https://github.com/guymano/focus-data-toolkit/compare/v0.9.0...v0.11.0rc1
|
|
@@ -49,6 +49,8 @@ pytest -m packaging # build + install a wheel/sdist (need
|
|
|
49
49
|
|
|
50
50
|
python scripts/check_pinned_actions.py # every GitHub Action is SHA/digest pinned
|
|
51
51
|
python scripts/verify_model_provenance.py # the embedded FOCUS model matches its provenance
|
|
52
|
+
python scripts/describe_generated_samples.py # independently audited sample statistics
|
|
53
|
+
python scripts/validate_official_samples.py --check-existing # archived reports + provenance
|
|
52
54
|
```
|
|
53
55
|
|
|
54
56
|
A PR is expected to be green on lint, types, and the default test suite, and to
|
|
@@ -63,7 +65,8 @@ identical toolkit version and identical parameters (`provider`, `focus_version`,
|
|
|
63
65
|
- Keep generator draws in a fixed order; do not introduce a clock, real RNG, or
|
|
64
66
|
environment-dependent behaviour into generation/conversion.
|
|
65
67
|
- Golden snapshots live in `tests/fixtures/golden/`:
|
|
66
|
-
- `compatibility_golden/` —
|
|
68
|
+
- `compatibility_golden/` — reviewed synthetic outputs with executable semantic checks
|
|
69
|
+
and documented residual official-model/validator failures.
|
|
67
70
|
These are a **byte-for-byte** intra-version contract.
|
|
68
71
|
- `correctness_migration/` — cases with a *known* prior defect: the old output
|
|
69
72
|
is archived for comparison, and the **new** output is the spec-correct one.
|
|
@@ -74,6 +77,11 @@ identical toolkit version and identical parameters (`provider`, `focus_version`,
|
|
|
74
77
|
- If a diff changes a snapshot you did **not** intend to touch, treat it as a
|
|
75
78
|
regression and investigate before updating the fixture.
|
|
76
79
|
|
|
80
|
+
Generator changes also require a fresh official-validation **candidate**, review
|
|
81
|
+
of every changed rule/state/count and explicit evidence promotion. See
|
|
82
|
+
[generator corrections](docs/generator-corrections.md). A successful reference
|
|
83
|
+
comparison does not certify complete FOCUS conformance.
|
|
84
|
+
|
|
77
85
|
## Changing the embedded FOCUS model
|
|
78
86
|
|
|
79
87
|
The FOCUS 1.4 model JSON (`src/focus_data_toolkit/model/focus_1_4_model.json`) is
|
|
@@ -18,7 +18,9 @@ include tools/extract_focus_1_4_model.py
|
|
|
18
18
|
recursive-include scripts *.py
|
|
19
19
|
recursive-include schema *.json
|
|
20
20
|
recursive-include docs *.md
|
|
21
|
+
include docs/generator-statistics.json
|
|
21
22
|
recursive-include tests *.py *.csv *.json *.md
|
|
23
|
+
recursive-include tests/fixtures/official/generator_validation *.log
|
|
22
24
|
|
|
23
25
|
global-exclude *.py[cod]
|
|
24
26
|
global-exclude __pycache__
|
|
@@ -46,6 +46,17 @@ documentation page it was authored against.
|
|
|
46
46
|
|
|
47
47
|
3. Optional dependency: the official FinOps FOCUS validator
|
|
48
48
|
-----------------------------------------------------------
|
|
49
|
+
The source test evidence at tests/fixtures/official/generator_validation includes
|
|
50
|
+
rule expressions from the FOCUS 1.2.0.1 and 1.3.0.1 models (FinOps Foundation,
|
|
51
|
+
CC-BY-4.0, source and license links in section 2 above) and captured validator
|
|
52
|
+
results. Model expressions are reproduced without modification; surrounding
|
|
53
|
+
explanations and synthetic example records are authored by this project.
|
|
54
|
+
|
|
55
|
+
Generator corrections adapt the behavior examined in FOCUS-Sample-Data PRs 6/7,
|
|
56
|
+
at commits e14921a3ba8d5f75a7b899d878e372999482ba9a and
|
|
57
|
+
99917010b27f7c0ca3586f8e0daab7e1c8103dac. See docs/generator-corrections.md for
|
|
58
|
+
source links and the deliberate semantic adaptations.
|
|
59
|
+
|
|
49
60
|
The optional `[validator]` extra installs `focus-validator` from PyPI, which is
|
|
50
61
|
published by the FinOps Foundation under its own license. It is not vendored or
|
|
51
62
|
redistributed by this project; it is resolved by your package manager on
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: focus-data-toolkit
|
|
3
|
+
Version: 0.13.0
|
|
4
|
+
Summary: Generate provider-realistic FOCUS 1.2/1.3 sample data (AWS, Azure, GCP) and convert it to the four FOCUS 1.4 datasets — strictly from source facts, completed by client supplements including native AWS/Azure/GCP exports — with schema detection, gap analysis, a cross-dataset validation gate and atomic writes.
|
|
5
|
+
Author: Guy-Hermann Adiko
|
|
6
|
+
License-Expression: MIT AND CC-BY-4.0
|
|
7
|
+
Project-URL: Homepage, https://github.com/guymano/focus-data-toolkit
|
|
8
|
+
Project-URL: Source, https://github.com/guymano/focus-data-toolkit
|
|
9
|
+
Project-URL: Issues, https://github.com/guymano/focus-data-toolkit/issues
|
|
10
|
+
Project-URL: Changelog, https://github.com/guymano/focus-data-toolkit/blob/main/CHANGELOG.md
|
|
11
|
+
Project-URL: Documentation, https://github.com/guymano/focus-data-toolkit#readme
|
|
12
|
+
Keywords: finops,focus,billing,cost,sample-data
|
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Topic :: Office/Business :: Financial
|
|
20
|
+
Classifier: Typing :: Typed
|
|
21
|
+
Requires-Python: >=3.11
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
License-File: LICENSE
|
|
24
|
+
License-File: NOTICE
|
|
25
|
+
License-File: LICENSES/CC-BY-4.0.txt
|
|
26
|
+
Provides-Extra: parquet
|
|
27
|
+
Requires-Dist: pyarrow<26,>=15; extra == "parquet"
|
|
28
|
+
Requires-Dist: tzdata>=2024.1; sys_platform == "win32" and extra == "parquet"
|
|
29
|
+
Provides-Extra: scale
|
|
30
|
+
Requires-Dist: focus-data-toolkit[parquet]; extra == "scale"
|
|
31
|
+
Provides-Extra: validator
|
|
32
|
+
Requires-Dist: focus-validator<3,>=2.1; python_version >= "3.12" and extra == "validator"
|
|
33
|
+
Provides-Extra: studio
|
|
34
|
+
Requires-Dist: fastapi<1,>=0.110; extra == "studio"
|
|
35
|
+
Requires-Dist: uvicorn[standard]<1,>=0.29; extra == "studio"
|
|
36
|
+
Requires-Dist: python-multipart<1,>=0.0.9; extra == "studio"
|
|
37
|
+
Provides-Extra: studio-all
|
|
38
|
+
Requires-Dist: focus-data-toolkit[parquet,studio]; extra == "studio-all"
|
|
39
|
+
Provides-Extra: all
|
|
40
|
+
Requires-Dist: focus-data-toolkit[parquet,studio,validator]; extra == "all"
|
|
41
|
+
Provides-Extra: release
|
|
42
|
+
Requires-Dist: build<2,>=1; extra == "release"
|
|
43
|
+
Requires-Dist: twine<8,>=5; extra == "release"
|
|
44
|
+
Provides-Extra: dev
|
|
45
|
+
Requires-Dist: focus-data-toolkit[parquet,release,studio]; extra == "dev"
|
|
46
|
+
Requires-Dist: pytest>=8; extra == "dev"
|
|
47
|
+
Requires-Dist: pytest-cov<8,>=5; extra == "dev"
|
|
48
|
+
Requires-Dist: ruff>=0.6; extra == "dev"
|
|
49
|
+
Requires-Dist: mypy<2.4,>=1.11; extra == "dev"
|
|
50
|
+
Requires-Dist: jsonschema<5,>=4.21; extra == "dev"
|
|
51
|
+
Requires-Dist: httpx<1,>=0.27; extra == "dev"
|
|
52
|
+
Dynamic: license-file
|
|
53
|
+
|
|
54
|
+
# focus-data-toolkit
|
|
55
|
+
|
|
56
|
+
Generate realistic **FOCUS 1.2 / 1.3** cost and usage data (AWS, Azure, GCP), convert it to
|
|
57
|
+
**FOCUS 1.4**, and validate the result. One dependency-free Python core, usable three ways.
|
|
58
|
+
|
|
59
|
+
[](https://pypi.org/project/focus-data-toolkit/)
|
|
60
|
+
[](https://pypi.org/project/focus-data-toolkit/)
|
|
61
|
+
[](LICENSE)
|
|
62
|
+
[](https://github.com/guymano/focus-data-toolkit/actions/workflows/ci.yml)
|
|
63
|
+
|
|
64
|
+
[FOCUS](https://focus.finops.org) is the open standard for cloud cost and usage data. FOCUS 1.4 defines four datasets: Cost and Usage, Contract Commitment, Billing Period, and Invoice Detail. The toolkit is honest by design: any value it cannot derive from your source is left empty (**strict** mode) or filled with clearly labelled assumptions (**synthetic** mode).
|
|
65
|
+
|
|
66
|
+
The source prepares **0.13.0** with corrected subscriptions, traceable taxes,
|
|
67
|
+
stable offers and partially used fleets of 500 machines. See the
|
|
68
|
+
[generator corrections and validation evidence](docs/generator-corrections.md)
|
|
69
|
+
for the new byte baseline and sample assumptions. The Docker examples below
|
|
70
|
+
continue to pin the previously released 0.12.0 image.
|
|
71
|
+
|
|
72
|
+
## Three ways to use it
|
|
73
|
+
|
|
74
|
+
| Interface | Best for | Get started |
|
|
75
|
+
|---|---|---|
|
|
76
|
+
| **Studio** | FinOps users who prefer a UI | `pip install "focus-data-toolkit[studio]"` then `focus-toolkit ui` |
|
|
77
|
+
| **Runner** | Automation and large volumes | `docker run --rm ghcr.io/guymano/focus-data-toolkit:0.12.0 version` |
|
|
78
|
+
| **CLI & SDK** | Engineers and scripts | `pip install focus-data-toolkit` then `focus-toolkit --help` |
|
|
79
|
+
|
|
80
|
+
All three run the same core, so their outputs are byte-for-byte identical. Studio is a local web app (binds `127.0.0.1`, token-guarded, no data leaves your machine, see [docs/studio.md](docs/studio.md)). Runner is a non-root OCI image whose entrypoint is the CLI (see [docs/runner.md](docs/runner.md)).
|
|
81
|
+
|
|
82
|
+
## Install
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
pip install focus-data-toolkit
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
The core needs only the standard library (Python 3.11+). Optional extras:
|
|
89
|
+
|
|
90
|
+
| Extra | Adds |
|
|
91
|
+
|---|---|
|
|
92
|
+
| `parquet` | Parquet I/O: columnar, decimal128, Hive partitioning (alias: `scale`) |
|
|
93
|
+
| `studio` | the local web UI (`focus-toolkit ui`) |
|
|
94
|
+
| `studio-all` | `studio` + `parquet` |
|
|
95
|
+
| `validator` | the official FinOps validator (`--official`, needs Python 3.12+) |
|
|
96
|
+
| `all` | everything above |
|
|
97
|
+
|
|
98
|
+
Also available via `pipx install`, `uv tool install`, or `docker pull ghcr.io/guymano/focus-data-toolkit:0.12.0`.
|
|
99
|
+
|
|
100
|
+
## Quickstart
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
# 1. Generate sample data (aws|azure|gcp, FOCUS 1.2|1.3)
|
|
104
|
+
focus-toolkit generate --provider aws --focus-version 1.3 --rows 1000 --out ./out
|
|
105
|
+
|
|
106
|
+
# 2. Convert a 1.2/1.3 Cost and Usage file to FOCUS 1.4 (source version auto-detected)
|
|
107
|
+
focus-toolkit convert --cost-and-usage out/focus_1_3_cost_and_usage_aws.csv --out ./focus-1.4
|
|
108
|
+
|
|
109
|
+
# 3. Open the Studio web app (needs the studio extra)
|
|
110
|
+
focus-toolkit ui
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Or use it as a Python library, the same engine behind all three interfaces:
|
|
114
|
+
|
|
115
|
+
```python
|
|
116
|
+
from focus_data_toolkit import convert_files
|
|
117
|
+
|
|
118
|
+
convert_files("cost_and_usage.csv", "focus-1.4", mode="strict")
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## What it does, and what it doesn't
|
|
122
|
+
|
|
123
|
+
- Converts FOCUS 1.2/1.3 Cost and Usage into the four FOCUS 1.4 datasets.
|
|
124
|
+
- The three other datasets come only from [supplements](docs/supplements.md) or synthetic mode.
|
|
125
|
+
There is no FOCUS 1.4 generator and no invalid-data generator.
|
|
126
|
+
- Built for real data: bounded-memory streaming (`--stream`), atomic writes, a deterministic
|
|
127
|
+
manifest with per-column lineage, structured `FDT-*` diagnostics, cross-dataset validation.
|
|
128
|
+
- Single-node engine. See [docs/compatibility.md](docs/compatibility.md) for the support matrix.
|
|
129
|
+
|
|
130
|
+
## Exit codes
|
|
131
|
+
|
|
132
|
+
| Code | Meaning |
|
|
133
|
+
|---|---|
|
|
134
|
+
| `0` | success, no assumptions |
|
|
135
|
+
| `1` | lint / validation / write failure |
|
|
136
|
+
| `2` | invalid input or arguments |
|
|
137
|
+
| `3` | strict result intentionally incomplete |
|
|
138
|
+
| `4` | synthetic result contains assumptions |
|
|
139
|
+
| `5` | disk space or budget exhausted (streaming / Runner) |
|
|
140
|
+
| `130` | cancelled (Ctrl-C / SIGTERM), nothing partial is published |
|
|
141
|
+
|
|
142
|
+
Add `--exit-policy pipeline` in `set -e` or CI scripts to treat codes `3` and `4` as `0`.
|
|
143
|
+
|
|
144
|
+
## Trust
|
|
145
|
+
|
|
146
|
+
- Deterministic: same input, same output bytes, all listed in `SHA256SUMS`.
|
|
147
|
+
- The embedded FOCUS 1.4 model is hash-pinned to the FinOps source workbook; see [docs/model-provenance.md](docs/model-provenance.md).
|
|
148
|
+
- Releases are reproducible, signed (Sigstore/cosign), with SBOM and attestations; see [docs/releasing.md](docs/releasing.md).
|
|
149
|
+
- Private: no network I/O, no telemetry, no credentials; see [docs/security-model.md](docs/security-model.md).
|
|
150
|
+
|
|
151
|
+
## Documentation
|
|
152
|
+
|
|
153
|
+
[Studio](docs/studio.md) · [Runner](docs/runner.md) · [Supplements](docs/supplements.md) · [Compatibility](docs/compatibility.md) · [Versioning](docs/versioning.md) · [Security model](docs/security-model.md) · [Model provenance](docs/model-provenance.md) · [Releasing](docs/releasing.md) · [Changelog](CHANGELOG.md) · [Contributing](CONTRIBUTING.md) · [Security policy](SECURITY.md)
|
|
154
|
+
|
|
155
|
+
## License
|
|
156
|
+
|
|
157
|
+
Code is MIT (see [LICENSE](LICENSE)). The embedded FOCUS 1.4 data model derives from the FinOps FOCUS workbook, © the FinOps Foundation, CC-BY-4.0 (see [NOTICE](NOTICE)). "FOCUS" and "FinOps" are FinOps Foundation trademarks; this is an independent community project, not endorsed by the FinOps Foundation.
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# focus-data-toolkit
|
|
2
|
+
|
|
3
|
+
Generate realistic **FOCUS 1.2 / 1.3** cost and usage data (AWS, Azure, GCP), convert it to
|
|
4
|
+
**FOCUS 1.4**, and validate the result. One dependency-free Python core, usable three ways.
|
|
5
|
+
|
|
6
|
+
[](https://pypi.org/project/focus-data-toolkit/)
|
|
7
|
+
[](https://pypi.org/project/focus-data-toolkit/)
|
|
8
|
+
[](LICENSE)
|
|
9
|
+
[](https://github.com/guymano/focus-data-toolkit/actions/workflows/ci.yml)
|
|
10
|
+
|
|
11
|
+
[FOCUS](https://focus.finops.org) is the open standard for cloud cost and usage data. FOCUS 1.4 defines four datasets: Cost and Usage, Contract Commitment, Billing Period, and Invoice Detail. The toolkit is honest by design: any value it cannot derive from your source is left empty (**strict** mode) or filled with clearly labelled assumptions (**synthetic** mode).
|
|
12
|
+
|
|
13
|
+
The source prepares **0.13.0** with corrected subscriptions, traceable taxes,
|
|
14
|
+
stable offers and partially used fleets of 500 machines. See the
|
|
15
|
+
[generator corrections and validation evidence](docs/generator-corrections.md)
|
|
16
|
+
for the new byte baseline and sample assumptions. The Docker examples below
|
|
17
|
+
continue to pin the previously released 0.12.0 image.
|
|
18
|
+
|
|
19
|
+
## Three ways to use it
|
|
20
|
+
|
|
21
|
+
| Interface | Best for | Get started |
|
|
22
|
+
|---|---|---|
|
|
23
|
+
| **Studio** | FinOps users who prefer a UI | `pip install "focus-data-toolkit[studio]"` then `focus-toolkit ui` |
|
|
24
|
+
| **Runner** | Automation and large volumes | `docker run --rm ghcr.io/guymano/focus-data-toolkit:0.12.0 version` |
|
|
25
|
+
| **CLI & SDK** | Engineers and scripts | `pip install focus-data-toolkit` then `focus-toolkit --help` |
|
|
26
|
+
|
|
27
|
+
All three run the same core, so their outputs are byte-for-byte identical. Studio is a local web app (binds `127.0.0.1`, token-guarded, no data leaves your machine, see [docs/studio.md](docs/studio.md)). Runner is a non-root OCI image whose entrypoint is the CLI (see [docs/runner.md](docs/runner.md)).
|
|
28
|
+
|
|
29
|
+
## Install
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
pip install focus-data-toolkit
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
The core needs only the standard library (Python 3.11+). Optional extras:
|
|
36
|
+
|
|
37
|
+
| Extra | Adds |
|
|
38
|
+
|---|---|
|
|
39
|
+
| `parquet` | Parquet I/O: columnar, decimal128, Hive partitioning (alias: `scale`) |
|
|
40
|
+
| `studio` | the local web UI (`focus-toolkit ui`) |
|
|
41
|
+
| `studio-all` | `studio` + `parquet` |
|
|
42
|
+
| `validator` | the official FinOps validator (`--official`, needs Python 3.12+) |
|
|
43
|
+
| `all` | everything above |
|
|
44
|
+
|
|
45
|
+
Also available via `pipx install`, `uv tool install`, or `docker pull ghcr.io/guymano/focus-data-toolkit:0.12.0`.
|
|
46
|
+
|
|
47
|
+
## Quickstart
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
# 1. Generate sample data (aws|azure|gcp, FOCUS 1.2|1.3)
|
|
51
|
+
focus-toolkit generate --provider aws --focus-version 1.3 --rows 1000 --out ./out
|
|
52
|
+
|
|
53
|
+
# 2. Convert a 1.2/1.3 Cost and Usage file to FOCUS 1.4 (source version auto-detected)
|
|
54
|
+
focus-toolkit convert --cost-and-usage out/focus_1_3_cost_and_usage_aws.csv --out ./focus-1.4
|
|
55
|
+
|
|
56
|
+
# 3. Open the Studio web app (needs the studio extra)
|
|
57
|
+
focus-toolkit ui
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Or use it as a Python library, the same engine behind all three interfaces:
|
|
61
|
+
|
|
62
|
+
```python
|
|
63
|
+
from focus_data_toolkit import convert_files
|
|
64
|
+
|
|
65
|
+
convert_files("cost_and_usage.csv", "focus-1.4", mode="strict")
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## What it does, and what it doesn't
|
|
69
|
+
|
|
70
|
+
- Converts FOCUS 1.2/1.3 Cost and Usage into the four FOCUS 1.4 datasets.
|
|
71
|
+
- The three other datasets come only from [supplements](docs/supplements.md) or synthetic mode.
|
|
72
|
+
There is no FOCUS 1.4 generator and no invalid-data generator.
|
|
73
|
+
- Built for real data: bounded-memory streaming (`--stream`), atomic writes, a deterministic
|
|
74
|
+
manifest with per-column lineage, structured `FDT-*` diagnostics, cross-dataset validation.
|
|
75
|
+
- Single-node engine. See [docs/compatibility.md](docs/compatibility.md) for the support matrix.
|
|
76
|
+
|
|
77
|
+
## Exit codes
|
|
78
|
+
|
|
79
|
+
| Code | Meaning |
|
|
80
|
+
|---|---|
|
|
81
|
+
| `0` | success, no assumptions |
|
|
82
|
+
| `1` | lint / validation / write failure |
|
|
83
|
+
| `2` | invalid input or arguments |
|
|
84
|
+
| `3` | strict result intentionally incomplete |
|
|
85
|
+
| `4` | synthetic result contains assumptions |
|
|
86
|
+
| `5` | disk space or budget exhausted (streaming / Runner) |
|
|
87
|
+
| `130` | cancelled (Ctrl-C / SIGTERM), nothing partial is published |
|
|
88
|
+
|
|
89
|
+
Add `--exit-policy pipeline` in `set -e` or CI scripts to treat codes `3` and `4` as `0`.
|
|
90
|
+
|
|
91
|
+
## Trust
|
|
92
|
+
|
|
93
|
+
- Deterministic: same input, same output bytes, all listed in `SHA256SUMS`.
|
|
94
|
+
- The embedded FOCUS 1.4 model is hash-pinned to the FinOps source workbook; see [docs/model-provenance.md](docs/model-provenance.md).
|
|
95
|
+
- Releases are reproducible, signed (Sigstore/cosign), with SBOM and attestations; see [docs/releasing.md](docs/releasing.md).
|
|
96
|
+
- Private: no network I/O, no telemetry, no credentials; see [docs/security-model.md](docs/security-model.md).
|
|
97
|
+
|
|
98
|
+
## Documentation
|
|
99
|
+
|
|
100
|
+
[Studio](docs/studio.md) · [Runner](docs/runner.md) · [Supplements](docs/supplements.md) · [Compatibility](docs/compatibility.md) · [Versioning](docs/versioning.md) · [Security model](docs/security-model.md) · [Model provenance](docs/model-provenance.md) · [Releasing](docs/releasing.md) · [Changelog](CHANGELOG.md) · [Contributing](CONTRIBUTING.md) · [Security policy](SECURITY.md)
|
|
101
|
+
|
|
102
|
+
## License
|
|
103
|
+
|
|
104
|
+
Code is MIT (see [LICENSE](LICENSE)). The embedded FOCUS 1.4 data model derives from the FinOps FOCUS workbook, © the FinOps Foundation, CC-BY-4.0 (see [NOTICE](NOTICE)). "FOCUS" and "FinOps" are FinOps Foundation trademarks; this is an independent community project, not endorsed by the FinOps Foundation.
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
# Generator corrections prepared for 0.13.0
|
|
2
|
+
|
|
3
|
+
This is an adapted port of [FOCUS-Sample-Data PR 6](https://github.com/FinOps-Open-Cost-and-Usage-Spec/FOCUS-Sample-Data/pull/6)
|
|
4
|
+
at `e14921a3ba8d5f75a7b899d878e372999482ba9a` and
|
|
5
|
+
[PR 7](https://github.com/FinOps-Open-Cost-and-Usage-Spec/FOCUS-Sample-Data/pull/7)
|
|
6
|
+
at `99917010b27f7c0ca3586f8e0daab7e1c8103dac`. These are examined commits,
|
|
7
|
+
not a dependency on the eventual merged PRs. The previous toolkit baseline is
|
|
8
|
+
`d0c27bac6d1909fa39fe45538fce3a9d391ae0f8` (0.12.0).
|
|
9
|
+
|
|
10
|
+
## Corrected behavior
|
|
11
|
+
|
|
12
|
+
| Area | Previous output | New output |
|
|
13
|
+
|---|---|---|
|
|
14
|
+
| Period subscription | Effective cost zero, losing the fee in amortized views | Effective cost equals billed cost; pricing-currency amount follows the same exact exchange rate |
|
|
15
|
+
| Tax | Independent random amount | Exactly 10% of each corresponding source amount on an earlier, previously untaxed Standard Usage record |
|
|
16
|
+
| SKU | Random identifiers and list-price jitter | Stable canonical offer identity and stable public price; a separate subscription offer |
|
|
17
|
+
| Storage | Generator registry omitted recognized storage properties; legacy redundancy values | One property registry; AWS Standard/Zonal and Azure Hot/Local storage values |
|
|
18
|
+
| AWS resource | Payer account and inferred namespace | Owning subaccount and explicit service namespace, also for allocated resources |
|
|
19
|
+
| Commitment | Two to four machine-hours per period | Fleet capacity 500 machine-hours per hourly period, partially used |
|
|
20
|
+
| Group budget | Builder could overflow; final slicing could hide it | Every builder respects its budget; empty groups fall back to ordinary usage; exact final row count |
|
|
21
|
+
| Ordinary 1.3 contract | Every ordinary Standard Usage row negotiated | Deterministic approximately 35% selection; 10% discount for selected rows, public price otherwise and on ordinary allocations |
|
|
22
|
+
| Official result | Set of FAIL rules; an empty report could pass | Full rule inventory, states, violations, totals, process result, pinned resources and reproducible evidence |
|
|
23
|
+
| Invoice aggregate | Rounded to six decimals | Exact sum, including after FOCUS 1.4 conversion and Parquet serialization |
|
|
24
|
+
|
|
25
|
+
The archived pre-change examples are in
|
|
26
|
+
[`pr67_before.json`](../tests/fixtures/golden/correctness_migration/pr67_before.json).
|
|
27
|
+
The corresponding corrected outputs are the regenerated provider/version CSVs in
|
|
28
|
+
[`compatibility_golden`](../tests/fixtures/golden/compatibility_golden/).
|
|
29
|
+
The independent audit in `scripts/sample_audit.py` checks semantics rather than
|
|
30
|
+
reusing generator builders. Deliberately corrupted subscriptions, taxes, SKUs,
|
|
31
|
+
owners, units, storage properties, contract parents and missing purchases must fail.
|
|
32
|
+
|
|
33
|
+
## Generation assumptions and identity
|
|
34
|
+
|
|
35
|
+
Taxes are illustrative, not tax advice or jurisdiction-specific billing logic.
|
|
36
|
+
The description contains a one-based **data record** reference (excluding the CSV
|
|
37
|
+
header). The tax inherits account, service, period, currencies and tags; each
|
|
38
|
+
taxable monetary column is multiplied from its own source, exactly once. If there
|
|
39
|
+
is no eligible untaxed source, the scheduled tax becomes ordinary usage.
|
|
40
|
+
|
|
41
|
+
Eligible Standard Usage includes a split-allocation child. In that case the tax
|
|
42
|
+
applies to that child's amount, not the total host charge. The source record
|
|
43
|
+
reference identifies the exact share. Tax rows do not copy `Allocated*` fields:
|
|
44
|
+
they are separate tax charges, not additional members of the source allocation
|
|
45
|
+
group. This intentional sample policy is tested explicitly.
|
|
46
|
+
|
|
47
|
+
Prices are synthetic public and negotiated rates, not current cloud price lists.
|
|
48
|
+
Offer identity includes provider, service, meter, region, unit and canonical SKU
|
|
49
|
+
properties, excluding seed, account, contract and pricing category. Price identity
|
|
50
|
+
also includes the public list prices and billing/pricing currencies. The fixed
|
|
51
|
+
illustrative exchange rates remain part of the provider profiles. Quantity and
|
|
52
|
+
price precision are bounded before multiplication; cost products are not rounded.
|
|
53
|
+
|
|
54
|
+
Each commitment period contains a purchase, **two partially used fleet records**,
|
|
55
|
+
and unused capacity. Used plus unused capacity is exactly 500; effective costs
|
|
56
|
+
sum to the purchase cost. Fleet URNs and `SyntheticFleetSize: 500` tags explicitly
|
|
57
|
+
describe synthetic aggregation rather than a single cloud machine. The fleet-size
|
|
58
|
+
tag deliberately uses the JSON number 500: it is a numeric synthetic measurement,
|
|
59
|
+
not an imitation of a provider's string-valued native tag export. The annual
|
|
60
|
+
capacity commitment is 500 × 8,760 = **4,380,000 machine-hours**, with the existing
|
|
61
|
+
unit price. Spend commitments retain their cost-based metric. All commitment
|
|
62
|
+
periods lie within their annual term, including samples crossing the billing-month
|
|
63
|
+
hour boundary.
|
|
64
|
+
|
|
65
|
+
In 1.3, eligible compute gets an ordinary usage-minimum term, storage a negotiated
|
|
66
|
+
rate term, and other services a minimum-spend term. Unselected usage and ordinary
|
|
67
|
+
allocations have no negotiated application. Discount commitments share a parent
|
|
68
|
+
contract in groups of at most three, with compatible provider/account/currency
|
|
69
|
+
identity. Parent dates span their terms. A generation-local registry supplies both
|
|
70
|
+
datasets and avoids state leaking between calls. Contract Commitment APIs now
|
|
71
|
+
accept keyword-only `include_credits=False`; pass the same rows, seed and options
|
|
72
|
+
when generating the two datasets separately.
|
|
73
|
+
|
|
74
|
+
## ContractApplied compatibility
|
|
75
|
+
|
|
76
|
+
Generated Spend elements contain applied cost; Usage elements contain applied
|
|
77
|
+
quantity and unit. Inapplicable properties are omitted. The parser still reads
|
|
78
|
+
older objects with explicit nulls and converts existing 1.3 objects carrying both
|
|
79
|
+
metrics without rewriting their meaning.
|
|
80
|
+
|
|
81
|
+
The 1.3 rule model both describes optional properties and requires five
|
|
82
|
+
properties per element. This conflict is documented in the
|
|
83
|
+
[examined upstream notes](https://github.com/guymano/FOCUS-Sample-Data/blob/99917010b27f7c0ca3586f8e0daab7e1c8103dac/FOCUS-1.3/validation/upstream-notes.md).
|
|
84
|
+
We preserve the toolkit's applicable metric branches. This differs deliberately
|
|
85
|
+
from the upstream sample object shape and remains visible in official failures.
|
|
86
|
+
|
|
87
|
+
## Reproducible official evidence
|
|
88
|
+
|
|
89
|
+
The reference uses **focus-validator 2.2.1**, models **1.2.0.1 / 1.3.0.1**,
|
|
90
|
+
applicability **ALL**, 1,000 rows, default seeds 1202/1302, credits disabled.
|
|
91
|
+
Both model hashes and the currency resource hash are checked before execution.
|
|
92
|
+
Dataset roots, dependencies and nested rule references independently determine
|
|
93
|
+
the expected rule inventory. Empty, duplicate, incomplete, inconsistent or crashed
|
|
94
|
+
reports fail. Any state or violation-count change fails the reference comparison,
|
|
95
|
+
including PASS becoming SKIPPED with no new FAIL rule.
|
|
96
|
+
|
|
97
|
+
[`baseline.json`](../tests/fixtures/official/generator_validation/baseline.json)
|
|
98
|
+
contains generation-source fingerprints (LF-normalized), exact CSV hashes,
|
|
99
|
+
resource versions/hashes, parameters, every rule result and per-failure evidence.
|
|
100
|
+
Source hashes remain a strict gate, including version and audit-script changes.
|
|
101
|
+
Even a source-only edit requires a reviewed new candidate; dataset hashes cover
|
|
102
|
+
the selected fixtures, while source provenance identifies the code used to
|
|
103
|
+
produce and interpret the evidence. Mismatches now list the changed files.
|
|
104
|
+
Each residual failure has its model expression, explanation, a minimal source
|
|
105
|
+
record and independently checked population where the count represents rows.
|
|
106
|
+
Composite failures count expressions instead of rows and are labeled separately.
|
|
107
|
+
Raw stdout/stderr logs are archived beside it; stdout hashes preserve their exact
|
|
108
|
+
original bytes. The nine archived stderr logs are required to be empty, and the
|
|
109
|
+
offline check verifies this. Successful live comparisons remove their temporary
|
|
110
|
+
files; failed runs retain them for investigation. Candidate directories persist.
|
|
111
|
+
Live log paths/timing can differ across operating systems, but
|
|
112
|
+
the complete semantic inventory must match.
|
|
113
|
+
|
|
114
|
+
| Dataset | Provider | PASS | FAIL | SKIPPED |
|
|
115
|
+
|---|---|---:|---:|---:|
|
|
116
|
+
| Cost and Usage 1.2 | AWS | 353 | 15 | 210 |
|
|
117
|
+
| Cost and Usage 1.2 | Azure / GCP, each | 357 | 11 | 210 |
|
|
118
|
+
| Cost and Usage 1.3 | AWS | 428 | 39 | 297 |
|
|
119
|
+
| Cost and Usage 1.3 | Azure / GCP, each | 432 | 35 | 297 |
|
|
120
|
+
| Contract Commitment 1.3 | Each provider | 76 | 0 | 38 |
|
|
121
|
+
|
|
122
|
+
Residual failures include AWS numeric-ID type inference, conditional/nullability
|
|
123
|
+
evaluation and the ContractApplied property-count conflict. These are **reviewed
|
|
124
|
+
non-regression results, not a conformance certificate**. Their counters were
|
|
125
|
+
reproduced from toolkit output, not copied from upstream PRs.
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
# Offline: no official dependency or network required
|
|
129
|
+
python scripts/validate_official_samples.py --check-existing
|
|
130
|
+
python scripts/describe_generated_samples.py
|
|
131
|
+
|
|
132
|
+
# Live reference comparison (Python 3.12+, isolated validator environment)
|
|
133
|
+
pip install focus-validator==2.2.1
|
|
134
|
+
python scripts/validate_official_samples.py
|
|
135
|
+
|
|
136
|
+
# A separate candidate for review; this never updates the committed reference
|
|
137
|
+
python scripts/validate_official_samples.py --record /tmp/new-focus-candidate
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Promotion requires reviewing the candidate's raw reports, semantic audit and
|
|
141
|
+
failure evidence, then explicitly copying its baseline and logs to the fixture
|
|
142
|
+
directory. CI only compares; it never records new expectations. The public
|
|
143
|
+
`validate --official` command shares the report parser, rejects FAIL even when the
|
|
144
|
+
subprocess returns zero, and applies **none** of the sample-only exceptions.
|
|
145
|
+
Its output is buffered until completion. It requires console output on stdout
|
|
146
|
+
and rejects conflicting output flags with exit code 2. An installed validator
|
|
147
|
+
version different from the tested 2.2.1 produces a warning; an incompatible or
|
|
148
|
+
incomplete console report fails with an explanatory message.
|
|
149
|
+
|
|
150
|
+
## Statistics and limits
|
|
151
|
+
|
|
152
|
+
[`generator-statistics.json`](generator-statistics.json) is generated by
|
|
153
|
+
`python scripts/describe_generated_samples.py --write`; the command without
|
|
154
|
+
`--write` verifies it. Amounts and ratios use Decimal arithmetic. Commitment share
|
|
155
|
+
is purchase cost / total billed cost; utilization and waste use used/unused
|
|
156
|
+
effective costs / commitment purchases. Compute coverage is covered list cost /
|
|
157
|
+
all eligible compute-usage list cost, excluding unused records. Contract application
|
|
158
|
+
counts include discount-backed usage/purchases as well as ordinary negotiated usage.
|
|
159
|
+
|
|
160
|
+
The six default fixtures have commitment share **18.4–30.9%**, utilization
|
|
161
|
+
**69.6–70.5%**, and compute coverage **99.2–99.96%**. The high compute coverage is a
|
|
162
|
+
consequence of fleets mixed with small ordinary usage, not a target or an estimate
|
|
163
|
+
of real customer behavior. The only pedagogical threshold is commitment share
|
|
164
|
+
at least 5% on the default 1,000-row fixtures. Small samples need not contain every
|
|
165
|
+
scenario. Closed synthetic periods reconcile billed/effective totals globally and
|
|
166
|
+
by account, period and currency; this is not imposed on client datasets.
|
|
167
|
+
|
|
168
|
+
## Migration and verification
|
|
169
|
+
|
|
170
|
+
Version 0.13.0 intentionally changes generated bytes and identities. CSV columns
|
|
171
|
+
and commands are preserved. Affected Parquet monetary columns use `decimal128(38,17)`;
|
|
172
|
+
unit prices retain their existing scales. The wider fractional scale reduces the
|
|
173
|
+
maximum integer digits to 21 for those columns. Nonrepresentable values fail
|
|
174
|
+
explicitly; no silent rounding is introduced. Pin 0.12.0 to reproduce old bytes.
|
|
175
|
+
|
|
176
|
+
Verification covers three providers, both source versions, credits on/off, seeds
|
|
177
|
+
0/1/42/default and sizes 1–12, 23/24/25, 100/1000/1001. FOCUS 1.4 conversion,
|
|
178
|
+
invoice aggregates, CSV/Parquet, partial allocations, interleaved generation calls,
|
|
179
|
+
contract references and Linux streaming/partitioned output are exercised. Strict
|
|
180
|
+
conversion of external data does not rewrite costs, taxes or SKUs to imitate the
|
|
181
|
+
synthetic generator.
|
|
182
|
+
|
|
183
|
+
### Local verification on 2026-09-05
|
|
184
|
+
|
|
185
|
+
| Check | Result |
|
|
186
|
+
|---|---|
|
|
187
|
+
| Complete default suite, Windows / Python 3.12 | 1,101 passed, 25 platform skips; 89.96% coverage |
|
|
188
|
+
| Complete default suite, Linux / Python 3.12 | 1,126 passed; 90.21% coverage |
|
|
189
|
+
| Targeted generation, golden, report and Parquet suite, Windows / Python 3.11 and 3.13 | 497 passed, 4 platform skips per version |
|
|
190
|
+
| Same targeted suite, Linux / Python 3.11 and 3.13 | 501 passed per version |
|
|
191
|
+
| Linux packaging and release checks | 13 passed, including wheel/sdist build and clean installation |
|
|
192
|
+
| Linux bounded-memory conversion, 100,000 then 300,000 rows | Passed; Python allocation peak stays below 200 MB and grows by less than 1.5x for 3x the rows (tracemalloc excludes native allocations) |
|
|
193
|
+
| Live official reference comparison | All nine complete reports match between Windows and Linux |
|
|
194
|
+
| Lint, types, action pins, model provenance, offline evidence and documented statistics | Passed |
|
|
195
|
+
|
|
196
|
+
These are local executions performed before PR creation. The repository's CI
|
|
197
|
+
retains its full OS/Python matrix, including the existing macOS smoke run; remote
|
|
198
|
+
results are reported on the PR. Publishing remains a separate release step.
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
{
|
|
2
|
+
"aws_1.2": {
|
|
3
|
+
"billed_cost": "18857.124623679033750",
|
|
4
|
+
"commitment_billed_cost": "5826.912000",
|
|
5
|
+
"commitment_share": "0.3090032078741794288132899939",
|
|
6
|
+
"compute_coverage": "0.9996244701943354539595341662",
|
|
7
|
+
"contract_applied_rows": 0,
|
|
8
|
+
"effective_cost": "18857.124623679033750",
|
|
9
|
+
"rows": 1000,
|
|
10
|
+
"utilization": "0.7020407406593406593406593407",
|
|
11
|
+
"waste": "0.2979592593406593406593406593"
|
|
12
|
+
},
|
|
13
|
+
"aws_1.3": {
|
|
14
|
+
"billed_cost": "18554.856257624590813",
|
|
15
|
+
"commitment_billed_cost": "4610.304000",
|
|
16
|
+
"commitment_share": "0.2484688609810990373610109813",
|
|
17
|
+
"commitments": 75,
|
|
18
|
+
"compute_coverage": "0.9926713446624324633475395163",
|
|
19
|
+
"contract_applied_rows": 626,
|
|
20
|
+
"contracts": 28,
|
|
21
|
+
"effective_cost": "18554.856257624590813",
|
|
22
|
+
"non_discount_terms": 3,
|
|
23
|
+
"rows": 1000,
|
|
24
|
+
"utilization": "0.7018307347222222222222222222",
|
|
25
|
+
"waste": "0.2981692652777777777777777778"
|
|
26
|
+
},
|
|
27
|
+
"azure_1.2": {
|
|
28
|
+
"billed_cost": "49321.108200244240000",
|
|
29
|
+
"commitment_billed_cost": "11653.824000",
|
|
30
|
+
"commitment_share": "0.2362847151099149435004291808",
|
|
31
|
+
"compute_coverage": "0.9994860707128948614490559558",
|
|
32
|
+
"contract_applied_rows": 0,
|
|
33
|
+
"effective_cost": "49321.108200244240000",
|
|
34
|
+
"rows": 1000,
|
|
35
|
+
"utilization": "0.7052545978021978021978021978",
|
|
36
|
+
"waste": "0.2947454021978021978021978022"
|
|
37
|
+
},
|
|
38
|
+
"azure_1.3": {
|
|
39
|
+
"billed_cost": "44516.766247198048000",
|
|
40
|
+
"commitment_billed_cost": "8196.096000",
|
|
41
|
+
"commitment_share": "0.1841125645669708672631528611",
|
|
42
|
+
"commitments": 67,
|
|
43
|
+
"compute_coverage": "0.9920858412453828140790998259",
|
|
44
|
+
"contract_applied_rows": 596,
|
|
45
|
+
"contracts": 25,
|
|
46
|
+
"effective_cost": "44516.766247198048000",
|
|
47
|
+
"non_discount_terms": 3,
|
|
48
|
+
"rows": 1000,
|
|
49
|
+
"utilization": "0.699760265625",
|
|
50
|
+
"waste": "0.300239734375"
|
|
51
|
+
},
|
|
52
|
+
"gcp_1.2": {
|
|
53
|
+
"billed_cost": "31758.210633880783500",
|
|
54
|
+
"commitment_billed_cost": "7418.374000",
|
|
55
|
+
"commitment_share": "0.2335891680271751825377137440",
|
|
56
|
+
"compute_coverage": "0.9993595790441745620531488744",
|
|
57
|
+
"contract_applied_rows": 0,
|
|
58
|
+
"effective_cost": "31758.210633880783500",
|
|
59
|
+
"rows": 1000,
|
|
60
|
+
"utilization": "0.6956325204819277108433734940",
|
|
61
|
+
"waste": "0.3043674795180722891566265060"
|
|
62
|
+
},
|
|
63
|
+
"gcp_1.3": {
|
|
64
|
+
"billed_cost": "21535.602792935027500",
|
|
65
|
+
"commitment_billed_cost": "6613.972000",
|
|
66
|
+
"commitment_share": "0.3071180344285408378488339428",
|
|
67
|
+
"commitments": 77,
|
|
68
|
+
"compute_coverage": "0.9935304486425862660442853958",
|
|
69
|
+
"contract_applied_rows": 640,
|
|
70
|
+
"contracts": 30,
|
|
71
|
+
"effective_cost": "21535.602792935027500",
|
|
72
|
+
"non_discount_terms": 3,
|
|
73
|
+
"rows": 1000,
|
|
74
|
+
"utilization": "0.6959978932432432432432432432",
|
|
75
|
+
"waste": "0.3040021067567567567567567568"
|
|
76
|
+
}
|
|
77
|
+
}
|