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.
Files changed (292) hide show
  1. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/CHANGELOG.md +23 -0
  2. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/CONTRIBUTING.md +9 -1
  3. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/MANIFEST.in +2 -0
  4. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/NOTICE +11 -0
  5. focus_data_toolkit-0.13.0/PKG-INFO +157 -0
  6. focus_data_toolkit-0.13.0/README.md +104 -0
  7. focus_data_toolkit-0.13.0/docs/generator-corrections.md +198 -0
  8. focus_data_toolkit-0.13.0/docs/generator-statistics.json +77 -0
  9. focus_data_toolkit-0.13.0/docs/pr53-review-followup.md +61 -0
  10. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/docs/versioning.md +8 -2
  11. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/pyproject.toml +3 -0
  12. focus_data_toolkit-0.13.0/scripts/__init__.py +1 -0
  13. focus_data_toolkit-0.13.0/scripts/describe_generated_samples.py +42 -0
  14. focus_data_toolkit-0.13.0/scripts/sample_audit.py +162 -0
  15. focus_data_toolkit-0.13.0/scripts/validate_official_samples.py +354 -0
  16. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/_version.py +1 -1
  17. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/cli.py +17 -3
  18. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/convert/invoice_detail.py +4 -1
  19. focus_data_toolkit-0.13.0/src/focus_data_toolkit/generators/engine/context.py +36 -0
  20. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/generators/engine/determinism.py +35 -21
  21. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/generators/engine/json_focus.py +11 -10
  22. focus_data_toolkit-0.13.0/src/focus_data_toolkit/generators/engine/ladder.py +86 -0
  23. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/generators/engine/scenarios_core.py +68 -53
  24. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/generators/engine/serialize.py +67 -50
  25. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/generators/providers/aws.py +6 -9
  26. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/generators/providers/azure.py +1 -6
  27. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/generators/providers/gcp.py +0 -5
  28. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/generators/providers/profile.py +2 -2
  29. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/generators/versions/v1_3.py +9 -25
  30. focus_data_toolkit-0.13.0/src/focus_data_toolkit/model/focus_1_4_decimal_scale.json +49 -0
  31. focus_data_toolkit-0.13.0/src/focus_data_toolkit/official_report.py +66 -0
  32. focus_data_toolkit-0.13.0/src/focus_data_toolkit/official_validator.py +117 -0
  33. focus_data_toolkit-0.13.0/src/focus_data_toolkit.egg-info/PKG-INFO +157 -0
  34. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit.egg-info/SOURCES.txt +32 -0
  35. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/fixtures/golden/README.md +8 -2
  36. focus_data_toolkit-0.13.0/tests/fixtures/golden/compatibility_golden/aws_1_2_cost_and_usage_rows100_seed42.csv +101 -0
  37. focus_data_toolkit-0.13.0/tests/fixtures/golden/compatibility_golden/aws_1_2_cost_and_usage_rows25_seed7.csv +26 -0
  38. focus_data_toolkit-0.13.0/tests/fixtures/golden/compatibility_golden/aws_1_2_cost_and_usage_rows25_seed7_credits.csv +26 -0
  39. focus_data_toolkit-0.13.0/tests/fixtures/golden/compatibility_golden/aws_1_3_contract_commitment_rows100_seed42.csv +12 -0
  40. focus_data_toolkit-0.13.0/tests/fixtures/golden/compatibility_golden/aws_1_3_cost_and_usage_rows100_seed42.csv +101 -0
  41. focus_data_toolkit-0.13.0/tests/fixtures/golden/compatibility_golden/aws_1_3_cost_and_usage_rows25_seed7.csv +26 -0
  42. focus_data_toolkit-0.13.0/tests/fixtures/golden/compatibility_golden/aws_1_3_cost_and_usage_rows25_seed7_credits.csv +26 -0
  43. focus_data_toolkit-0.13.0/tests/fixtures/golden/compatibility_golden/azure_1_2_cost_and_usage_rows100_seed42.csv +101 -0
  44. focus_data_toolkit-0.13.0/tests/fixtures/golden/compatibility_golden/azure_1_2_cost_and_usage_rows25_seed7.csv +26 -0
  45. focus_data_toolkit-0.13.0/tests/fixtures/golden/compatibility_golden/azure_1_2_cost_and_usage_rows25_seed7_credits.csv +26 -0
  46. focus_data_toolkit-0.13.0/tests/fixtures/golden/compatibility_golden/azure_1_3_contract_commitment_rows100_seed42.csv +10 -0
  47. focus_data_toolkit-0.13.0/tests/fixtures/golden/compatibility_golden/azure_1_3_cost_and_usage_rows100_seed42.csv +101 -0
  48. focus_data_toolkit-0.13.0/tests/fixtures/golden/compatibility_golden/azure_1_3_cost_and_usage_rows25_seed7.csv +26 -0
  49. focus_data_toolkit-0.13.0/tests/fixtures/golden/compatibility_golden/azure_1_3_cost_and_usage_rows25_seed7_credits.csv +26 -0
  50. focus_data_toolkit-0.13.0/tests/fixtures/golden/compatibility_golden/gcp_1_2_cost_and_usage_rows100_seed42.csv +101 -0
  51. focus_data_toolkit-0.13.0/tests/fixtures/golden/compatibility_golden/gcp_1_2_cost_and_usage_rows25_seed7.csv +26 -0
  52. focus_data_toolkit-0.13.0/tests/fixtures/golden/compatibility_golden/gcp_1_2_cost_and_usage_rows25_seed7_credits.csv +26 -0
  53. focus_data_toolkit-0.13.0/tests/fixtures/golden/compatibility_golden/gcp_1_3_contract_commitment_rows100_seed42.csv +12 -0
  54. focus_data_toolkit-0.13.0/tests/fixtures/golden/compatibility_golden/gcp_1_3_cost_and_usage_rows100_seed42.csv +101 -0
  55. focus_data_toolkit-0.13.0/tests/fixtures/golden/compatibility_golden/gcp_1_3_cost_and_usage_rows25_seed7.csv +26 -0
  56. focus_data_toolkit-0.13.0/tests/fixtures/golden/compatibility_golden/gcp_1_3_cost_and_usage_rows25_seed7_credits.csv +26 -0
  57. focus_data_toolkit-0.13.0/tests/fixtures/golden/correctness_migration/README.md +10 -0
  58. focus_data_toolkit-0.13.0/tests/fixtures/golden/correctness_migration/pr67_before.json +815 -0
  59. focus_data_toolkit-0.13.0/tests/fixtures/official/generator_validation/README.md +15 -0
  60. focus_data_toolkit-0.13.0/tests/fixtures/official/generator_validation/aws_1.2_CostAndUsage.log +625 -0
  61. focus_data_toolkit-0.13.0/tests/fixtures/official/generator_validation/aws_1.2_CostAndUsage.stderr.log +0 -0
  62. focus_data_toolkit-0.13.0/tests/fixtures/official/generator_validation/aws_1.3_ContractCommitment.log +117 -0
  63. focus_data_toolkit-0.13.0/tests/fixtures/official/generator_validation/aws_1.3_ContractCommitment.stderr.log +0 -0
  64. focus_data_toolkit-0.13.0/tests/fixtures/official/generator_validation/aws_1.3_CostAndUsage.log +865 -0
  65. focus_data_toolkit-0.13.0/tests/fixtures/official/generator_validation/aws_1.3_CostAndUsage.stderr.log +0 -0
  66. focus_data_toolkit-0.13.0/tests/fixtures/official/generator_validation/azure_1.2_CostAndUsage.log +617 -0
  67. focus_data_toolkit-0.13.0/tests/fixtures/official/generator_validation/azure_1.2_CostAndUsage.stderr.log +0 -0
  68. focus_data_toolkit-0.13.0/tests/fixtures/official/generator_validation/azure_1.3_ContractCommitment.log +117 -0
  69. focus_data_toolkit-0.13.0/tests/fixtures/official/generator_validation/azure_1.3_ContractCommitment.stderr.log +0 -0
  70. focus_data_toolkit-0.13.0/tests/fixtures/official/generator_validation/azure_1.3_CostAndUsage.log +857 -0
  71. focus_data_toolkit-0.13.0/tests/fixtures/official/generator_validation/azure_1.3_CostAndUsage.stderr.log +0 -0
  72. focus_data_toolkit-0.13.0/tests/fixtures/official/generator_validation/baseline.json +35853 -0
  73. focus_data_toolkit-0.13.0/tests/fixtures/official/generator_validation/gcp_1.2_CostAndUsage.log +617 -0
  74. focus_data_toolkit-0.13.0/tests/fixtures/official/generator_validation/gcp_1.2_CostAndUsage.stderr.log +0 -0
  75. focus_data_toolkit-0.13.0/tests/fixtures/official/generator_validation/gcp_1.3_ContractCommitment.log +117 -0
  76. focus_data_toolkit-0.13.0/tests/fixtures/official/generator_validation/gcp_1.3_ContractCommitment.stderr.log +0 -0
  77. focus_data_toolkit-0.13.0/tests/fixtures/official/generator_validation/gcp_1.3_CostAndUsage.log +857 -0
  78. focus_data_toolkit-0.13.0/tests/fixtures/official/generator_validation/gcp_1.3_CostAndUsage.stderr.log +0 -0
  79. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_convert_roundtrip.py +1 -1
  80. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_cross_provider.py +2 -2
  81. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_fake_provider.py +0 -1
  82. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_generated_conformance.py +35 -17
  83. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_generators.py +3 -1
  84. focus_data_toolkit-0.13.0/tests/test_official_report.py +146 -0
  85. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_official_validator.py +2 -2
  86. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_parquet.py +3 -3
  87. focus_data_toolkit-0.13.0/tests/test_reviewed_roundtrip.py +78 -0
  88. focus_data_toolkit-0.13.0/tests/test_reviewed_sample_semantics.py +150 -0
  89. focus_data_toolkit-0.12.0/PKG-INFO +0 -196
  90. focus_data_toolkit-0.12.0/README.md +0 -143
  91. focus_data_toolkit-0.12.0/scripts/validate_official_samples.py +0 -353
  92. focus_data_toolkit-0.12.0/src/focus_data_toolkit/generators/engine/context.py +0 -12
  93. focus_data_toolkit-0.12.0/src/focus_data_toolkit/generators/engine/ladder.py +0 -71
  94. focus_data_toolkit-0.12.0/src/focus_data_toolkit/model/focus_1_4_decimal_scale.json +0 -10
  95. focus_data_toolkit-0.12.0/src/focus_data_toolkit/official_validator.py +0 -61
  96. focus_data_toolkit-0.12.0/src/focus_data_toolkit.egg-info/PKG-INFO +0 -196
  97. focus_data_toolkit-0.12.0/tests/fixtures/golden/compatibility_golden/aws_1_2_cost_and_usage_rows100_seed42.csv +0 -101
  98. focus_data_toolkit-0.12.0/tests/fixtures/golden/compatibility_golden/aws_1_2_cost_and_usage_rows25_seed7.csv +0 -26
  99. focus_data_toolkit-0.12.0/tests/fixtures/golden/compatibility_golden/aws_1_2_cost_and_usage_rows25_seed7_credits.csv +0 -26
  100. focus_data_toolkit-0.12.0/tests/fixtures/golden/compatibility_golden/aws_1_3_contract_commitment_rows100_seed42.csv +0 -11
  101. focus_data_toolkit-0.12.0/tests/fixtures/golden/compatibility_golden/aws_1_3_cost_and_usage_rows100_seed42.csv +0 -101
  102. focus_data_toolkit-0.12.0/tests/fixtures/golden/compatibility_golden/aws_1_3_cost_and_usage_rows25_seed7.csv +0 -26
  103. focus_data_toolkit-0.12.0/tests/fixtures/golden/compatibility_golden/aws_1_3_cost_and_usage_rows25_seed7_credits.csv +0 -26
  104. focus_data_toolkit-0.12.0/tests/fixtures/golden/compatibility_golden/azure_1_2_cost_and_usage_rows100_seed42.csv +0 -101
  105. focus_data_toolkit-0.12.0/tests/fixtures/golden/compatibility_golden/azure_1_2_cost_and_usage_rows25_seed7.csv +0 -26
  106. focus_data_toolkit-0.12.0/tests/fixtures/golden/compatibility_golden/azure_1_2_cost_and_usage_rows25_seed7_credits.csv +0 -26
  107. focus_data_toolkit-0.12.0/tests/fixtures/golden/compatibility_golden/azure_1_3_contract_commitment_rows100_seed42.csv +0 -11
  108. focus_data_toolkit-0.12.0/tests/fixtures/golden/compatibility_golden/azure_1_3_cost_and_usage_rows100_seed42.csv +0 -101
  109. focus_data_toolkit-0.12.0/tests/fixtures/golden/compatibility_golden/azure_1_3_cost_and_usage_rows25_seed7.csv +0 -26
  110. focus_data_toolkit-0.12.0/tests/fixtures/golden/compatibility_golden/azure_1_3_cost_and_usage_rows25_seed7_credits.csv +0 -26
  111. focus_data_toolkit-0.12.0/tests/fixtures/golden/compatibility_golden/gcp_1_2_cost_and_usage_rows100_seed42.csv +0 -101
  112. focus_data_toolkit-0.12.0/tests/fixtures/golden/compatibility_golden/gcp_1_2_cost_and_usage_rows25_seed7.csv +0 -26
  113. focus_data_toolkit-0.12.0/tests/fixtures/golden/compatibility_golden/gcp_1_2_cost_and_usage_rows25_seed7_credits.csv +0 -26
  114. focus_data_toolkit-0.12.0/tests/fixtures/golden/compatibility_golden/gcp_1_3_contract_commitment_rows100_seed42.csv +0 -12
  115. focus_data_toolkit-0.12.0/tests/fixtures/golden/compatibility_golden/gcp_1_3_cost_and_usage_rows100_seed42.csv +0 -101
  116. focus_data_toolkit-0.12.0/tests/fixtures/golden/compatibility_golden/gcp_1_3_cost_and_usage_rows25_seed7.csv +0 -26
  117. focus_data_toolkit-0.12.0/tests/fixtures/golden/compatibility_golden/gcp_1_3_cost_and_usage_rows25_seed7_credits.csv +0 -26
  118. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/LICENSE +0 -0
  119. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/LICENSES/CC-BY-4.0.txt +0 -0
  120. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/SECURITY.md +0 -0
  121. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/docs/audit/2026-07-improvement-plan.md +0 -0
  122. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/docs/audit/2026-07-repo-audit.md +0 -0
  123. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/docs/compatibility.md +0 -0
  124. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/docs/model-provenance.md +0 -0
  125. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/docs/releasing.md +0 -0
  126. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/docs/runner.md +0 -0
  127. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/docs/security-model.md +0 -0
  128. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/docs/studio.md +0 -0
  129. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/docs/supplements.md +0 -0
  130. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/schema/model_provenance.schema.json +0 -0
  131. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/scripts/check_pinned_actions.py +0 -0
  132. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/scripts/generate_resolved_sbom.py +0 -0
  133. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/scripts/generate_sbom.py +0 -0
  134. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/scripts/regenerate_golden_fixtures.py +0 -0
  135. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/scripts/verify_model_provenance.py +0 -0
  136. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/scripts/verify_release.py +0 -0
  137. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/setup.cfg +0 -0
  138. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/__init__.py +0 -0
  139. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/__main__.py +0 -0
  140. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/context/__init__.py +0 -0
  141. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/context/billing.py +0 -0
  142. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/context/provider.py +0 -0
  143. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/convert/__init__.py +0 -0
  144. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/convert/billing_period.py +0 -0
  145. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/convert/contract_applied.py +0 -0
  146. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/convert/contract_commitment.py +0 -0
  147. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/convert/cost_and_usage.py +0 -0
  148. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/convert/detect.py +0 -0
  149. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/convert/streaming.py +0 -0
  150. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/errors.py +0 -0
  151. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/focus_json.py +0 -0
  152. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/generators/__init__.py +0 -0
  153. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/generators/_shim.py +0 -0
  154. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/generators/engine/__init__.py +0 -0
  155. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/generators/engine/allocation_math.py +0 -0
  156. {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
  157. {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
  158. {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
  159. {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
  160. {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
  161. {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
  162. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/generators/providers/__init__.py +0 -0
  163. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/generators/scenarios.py +0 -0
  164. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/generators/versions/__init__.py +0 -0
  165. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/generators/versions/adapter.py +0 -0
  166. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/generators/versions/v1_2.py +0 -0
  167. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/io/__init__.py +0 -0
  168. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/io/atomic_writer.py +0 -0
  169. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/io/csv_io.py +0 -0
  170. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/io/parquet_io.py +0 -0
  171. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/io/records.py +0 -0
  172. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/io/row_source.py +0 -0
  173. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/lifecycle.py +0 -0
  174. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/manifest.py +0 -0
  175. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/model/__init__.py +0 -0
  176. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/model/capabilities.py +0 -0
  177. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/model/focus_1_4_model.json +0 -0
  178. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/model/focus_1_4_servicesubcategory.json +0 -0
  179. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/model/focus_json_keys.py +0 -0
  180. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/model/iso_4217_currencies.json +0 -0
  181. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/model/json_schema_check.py +0 -0
  182. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/model/json_schemas/allocatedmethoddetailsobjectschema.json +0 -0
  183. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/model/json_schemas/commitmentprogrameligibilitydetailsobjectschema.json +0 -0
  184. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/model/json_schemas/contractappliedobjectschema.json +0 -0
  185. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/model/json_schemas/contractcommitmentapplicabilityobjectschema.json +0 -0
  186. {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
  187. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/model/model_provenance.json +0 -0
  188. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/model/validator.py +0 -0
  189. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/modes.py +0 -0
  190. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/progress.py +0 -0
  191. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/provenance.py +0 -0
  192. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/py.typed +0 -0
  193. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/runtime.py +0 -0
  194. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/schema/__init__.py +0 -0
  195. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/schema/detection.py +0 -0
  196. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/schema/registry.py +0 -0
  197. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/storage/__init__.py +0 -0
  198. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/storage/external_index.py +0 -0
  199. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/storage/spill.py +0 -0
  200. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/studio/__init__.py +0 -0
  201. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/studio/app.py +0 -0
  202. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/studio/config.py +0 -0
  203. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/studio/frontend/app.js +0 -0
  204. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/studio/frontend/index.html +0 -0
  205. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/studio/frontend/style.css +0 -0
  206. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/studio/jobs.py +0 -0
  207. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/studio/preview.py +0 -0
  208. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/studio/security.py +0 -0
  209. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/studio/server.py +0 -0
  210. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/supplement/__init__.py +0 -0
  211. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/supplement/adapters/__init__.py +0 -0
  212. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/supplement/adapters/adapters_provenance.json +0 -0
  213. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/supplement/adapters/aws_invoice_summary.json +0 -0
  214. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/supplement/adapters/aws_savings_plans.json +0 -0
  215. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/supplement/adapters/azure_invoice.json +0 -0
  216. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/supplement/adapters/gcp_compute_commitments.json +0 -0
  217. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/supplement/adapters/registry.py +0 -0
  218. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/supplement/apply.py +0 -0
  219. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/supplement/gaps.py +0 -0
  220. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/supplement/kinds.py +0 -0
  221. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/supplement/loader.py +0 -0
  222. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/supplement/spec.py +0 -0
  223. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/supplement/validate.py +0 -0
  224. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/validate/__init__.py +0 -0
  225. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/validate/allocation.py +0 -0
  226. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/validate/bundle.py +0 -0
  227. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/validate/codes.py +0 -0
  228. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/validate/corrections.py +0 -0
  229. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/validate/reconciliation.py +0 -0
  230. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit/validate/referential.py +0 -0
  231. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit.egg-info/dependency_links.txt +0 -0
  232. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit.egg-info/entry_points.txt +0 -0
  233. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit.egg-info/requires.txt +0 -0
  234. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/src/focus_data_toolkit.egg-info/top_level.txt +0 -0
  235. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/conftest.py +0 -0
  236. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/fixtures/client_like/SOURCES.md +0 -0
  237. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/fixtures/client_like/consolidated_multi_provider_1_3.csv +0 -0
  238. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/fixtures/golden/compatibility_golden/scenarios_correction_set.csv +0 -0
  239. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/fixtures/golden/compatibility_golden/scenarios_sca_equal.csv +0 -0
  240. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/fixtures/golden/compatibility_golden/scenarios_sca_negative.csv +0 -0
  241. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/fixtures/golden/compatibility_golden/scenarios_sca_weighted.csv +0 -0
  242. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/fixtures/official/SOURCES.md +0 -0
  243. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/fixtures/official/invoice_detail_grain_example.json +0 -0
  244. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/fixtures/official/numeric_format_examples.json +0 -0
  245. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_adapters_aws.py +0 -0
  246. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_adapters_azure_gcp.py +0 -0
  247. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_atomic_write.py +0 -0
  248. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_billing_lifecycle.py +0 -0
  249. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_bundle_gate.py +0 -0
  250. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_bundle_validation.py +0 -0
  251. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_capabilities.py +0 -0
  252. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_cli.py +0 -0
  253. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_client_like.py +0 -0
  254. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_container.py +0 -0
  255. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_contract_applied.py +0 -0
  256. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_contract_commitment_semantics.py +0 -0
  257. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_corrections.py +0 -0
  258. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_detect.py +0 -0
  259. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_fixtures_are_synthetic.py +0 -0
  260. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_focus_json.py +0 -0
  261. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_gaps.py +0 -0
  262. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_generator_golden.py +0 -0
  263. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_grouping_keys.py +0 -0
  264. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_lifecycle_chains.py +0 -0
  265. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_lineage_counters.py +0 -0
  266. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_lint_focus.py +0 -0
  267. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_manifest.py +0 -0
  268. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_model_provenance.py +0 -0
  269. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_multi_provider.py +0 -0
  270. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_official_json_schemas.py +0 -0
  271. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_packaging.py +0 -0
  272. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_parquet_input.py +0 -0
  273. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_participant_entities.py +0 -0
  274. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_partitioning.py +0 -0
  275. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_progress_cancel.py +0 -0
  276. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_release_tooling.py +0 -0
  277. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_replace_recovery.py +0 -0
  278. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_runtime.py +0 -0
  279. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_schema_detection.py +0 -0
  280. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_single_source_focus_rules.py +0 -0
  281. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_spill.py +0 -0
  282. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_split_allocation.py +0 -0
  283. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_streaming.py +0 -0
  284. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_strict_conversion.py +0 -0
  285. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_studio.py +0 -0
  286. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_supplement_apply.py +0 -0
  287. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_supplement_loader.py +0 -0
  288. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_supplement_streaming.py +0 -0
  289. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_synthetic_conversion.py +0 -0
  290. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_validator.py +0 -0
  291. {focus_data_toolkit-0.12.0 → focus_data_toolkit-0.13.0}/tests/test_workflow_pins.py +0 -0
  292. {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/` — outputs verified correct against the FOCUS spec.
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
+ [![PyPI](https://img.shields.io/pypi/v/focus-data-toolkit)](https://pypi.org/project/focus-data-toolkit/)
60
+ [![Python](https://img.shields.io/pypi/pyversions/focus-data-toolkit)](https://pypi.org/project/focus-data-toolkit/)
61
+ [![License: MIT AND CC-BY-4.0](https://img.shields.io/badge/license-MIT%20AND%20CC--BY--4.0-blue)](LICENSE)
62
+ [![CI](https://github.com/guymano/focus-data-toolkit/actions/workflows/ci.yml/badge.svg)](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
+ [![PyPI](https://img.shields.io/pypi/v/focus-data-toolkit)](https://pypi.org/project/focus-data-toolkit/)
7
+ [![Python](https://img.shields.io/pypi/pyversions/focus-data-toolkit)](https://pypi.org/project/focus-data-toolkit/)
8
+ [![License: MIT AND CC-BY-4.0](https://img.shields.io/badge/license-MIT%20AND%20CC--BY--4.0-blue)](LICENSE)
9
+ [![CI](https://github.com/guymano/focus-data-toolkit/actions/workflows/ci.yml/badge.svg)](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
+ }