focus-data-toolkit 0.11.0__py3-none-any.whl
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/__init__.py +69 -0
- focus_data_toolkit/__main__.py +6 -0
- focus_data_toolkit/_version.py +8 -0
- focus_data_toolkit/cli.py +968 -0
- focus_data_toolkit/context/__init__.py +88 -0
- focus_data_toolkit/context/billing.py +54 -0
- focus_data_toolkit/context/provider.py +90 -0
- focus_data_toolkit/convert/__init__.py +708 -0
- focus_data_toolkit/convert/billing_period.py +65 -0
- focus_data_toolkit/convert/contract_applied.py +235 -0
- focus_data_toolkit/convert/contract_commitment.py +182 -0
- focus_data_toolkit/convert/cost_and_usage.py +179 -0
- focus_data_toolkit/convert/detect.py +39 -0
- focus_data_toolkit/convert/invoice_detail.py +199 -0
- focus_data_toolkit/convert/streaming.py +1030 -0
- focus_data_toolkit/errors.py +145 -0
- focus_data_toolkit/focus_json.py +68 -0
- focus_data_toolkit/generators/__init__.py +61 -0
- focus_data_toolkit/generators/_shim.py +43 -0
- focus_data_toolkit/generators/engine/__init__.py +14 -0
- focus_data_toolkit/generators/engine/context.py +12 -0
- focus_data_toolkit/generators/engine/determinism.py +117 -0
- focus_data_toolkit/generators/engine/json_focus.py +63 -0
- focus_data_toolkit/generators/engine/ladder.py +71 -0
- focus_data_toolkit/generators/engine/scenarios_core.py +380 -0
- focus_data_toolkit/generators/engine/serialize.py +151 -0
- focus_data_toolkit/generators/generate_aws_focus_1_2.py +19 -0
- focus_data_toolkit/generators/generate_aws_focus_1_3.py +20 -0
- focus_data_toolkit/generators/generate_azure_focus_1_2.py +17 -0
- focus_data_toolkit/generators/generate_azure_focus_1_3.py +17 -0
- focus_data_toolkit/generators/generate_gcp_focus_1_2.py +17 -0
- focus_data_toolkit/generators/generate_gcp_focus_1_3.py +17 -0
- focus_data_toolkit/generators/providers/__init__.py +29 -0
- focus_data_toolkit/generators/providers/aws.py +186 -0
- focus_data_toolkit/generators/providers/azure.py +191 -0
- focus_data_toolkit/generators/providers/gcp.py +194 -0
- focus_data_toolkit/generators/providers/profile.py +123 -0
- focus_data_toolkit/generators/scenarios.py +178 -0
- focus_data_toolkit/generators/versions/__init__.py +17 -0
- focus_data_toolkit/generators/versions/adapter.py +41 -0
- focus_data_toolkit/generators/versions/v1_2.py +111 -0
- focus_data_toolkit/generators/versions/v1_3.py +154 -0
- focus_data_toolkit/io/__init__.py +1 -0
- focus_data_toolkit/io/atomic_writer.py +462 -0
- focus_data_toolkit/io/csv_io.py +128 -0
- focus_data_toolkit/io/parquet_io.py +528 -0
- focus_data_toolkit/io/records.py +92 -0
- focus_data_toolkit/io/row_source.py +117 -0
- focus_data_toolkit/lifecycle.py +342 -0
- focus_data_toolkit/manifest.py +114 -0
- focus_data_toolkit/model/__init__.py +43 -0
- focus_data_toolkit/model/capabilities.py +66 -0
- focus_data_toolkit/model/focus_1_4_decimal_scale.json +10 -0
- focus_data_toolkit/model/focus_1_4_model.json +1913 -0
- focus_data_toolkit/model/focus_1_4_servicesubcategory.json +84 -0
- focus_data_toolkit/model/focus_json_keys.py +112 -0
- focus_data_toolkit/model/iso_4217_currencies.json +23 -0
- focus_data_toolkit/model/json_schema_check.py +205 -0
- focus_data_toolkit/model/json_schemas/allocatedmethoddetailsobjectschema.json +82 -0
- focus_data_toolkit/model/json_schemas/commitmentprogrameligibilitydetailsobjectschema.json +41 -0
- focus_data_toolkit/model/json_schemas/contractappliedobjectschema.json +104 -0
- focus_data_toolkit/model/json_schemas/contractcommitmentapplicabilityobjectschema.json +290 -0
- focus_data_toolkit/model/json_schemas/json_schemas_provenance.json +38 -0
- focus_data_toolkit/model/model_provenance.json +58 -0
- focus_data_toolkit/model/validator.py +498 -0
- focus_data_toolkit/modes.py +18 -0
- focus_data_toolkit/official_validator.py +61 -0
- focus_data_toolkit/progress.py +89 -0
- focus_data_toolkit/provenance.py +106 -0
- focus_data_toolkit/py.typed +1 -0
- focus_data_toolkit/runtime.py +243 -0
- focus_data_toolkit/schema/__init__.py +17 -0
- focus_data_toolkit/schema/detection.py +274 -0
- focus_data_toolkit/schema/registry.py +127 -0
- focus_data_toolkit/storage/__init__.py +1 -0
- focus_data_toolkit/storage/external_index.py +99 -0
- focus_data_toolkit/storage/spill.py +150 -0
- focus_data_toolkit/studio/__init__.py +19 -0
- focus_data_toolkit/studio/app.py +467 -0
- focus_data_toolkit/studio/config.py +42 -0
- focus_data_toolkit/studio/frontend/app.js +214 -0
- focus_data_toolkit/studio/frontend/index.html +101 -0
- focus_data_toolkit/studio/frontend/style.css +60 -0
- focus_data_toolkit/studio/jobs.py +142 -0
- focus_data_toolkit/studio/preview.py +32 -0
- focus_data_toolkit/studio/security.py +125 -0
- focus_data_toolkit/studio/server.py +71 -0
- focus_data_toolkit/supplement/__init__.py +50 -0
- focus_data_toolkit/supplement/adapters/__init__.py +21 -0
- focus_data_toolkit/supplement/adapters/adapters_provenance.json +39 -0
- focus_data_toolkit/supplement/adapters/aws_invoice_summary.json +24 -0
- focus_data_toolkit/supplement/adapters/aws_savings_plans.json +31 -0
- focus_data_toolkit/supplement/adapters/azure_invoice.json +25 -0
- focus_data_toolkit/supplement/adapters/gcp_compute_commitments.json +28 -0
- focus_data_toolkit/supplement/adapters/registry.py +215 -0
- focus_data_toolkit/supplement/apply.py +318 -0
- focus_data_toolkit/supplement/gaps.py +219 -0
- focus_data_toolkit/supplement/kinds.py +118 -0
- focus_data_toolkit/supplement/loader.py +409 -0
- focus_data_toolkit/supplement/spec.py +74 -0
- focus_data_toolkit/supplement/validate.py +215 -0
- focus_data_toolkit/validate/__init__.py +15 -0
- focus_data_toolkit/validate/allocation.py +333 -0
- focus_data_toolkit/validate/bundle.py +254 -0
- focus_data_toolkit/validate/codes.py +93 -0
- focus_data_toolkit/validate/corrections.py +245 -0
- focus_data_toolkit/validate/reconciliation.py +98 -0
- focus_data_toolkit/validate/referential.py +289 -0
- focus_data_toolkit-0.11.0.dist-info/METADATA +519 -0
- focus_data_toolkit-0.11.0.dist-info/RECORD +116 -0
- focus_data_toolkit-0.11.0.dist-info/WHEEL +5 -0
- focus_data_toolkit-0.11.0.dist-info/entry_points.txt +2 -0
- focus_data_toolkit-0.11.0.dist-info/licenses/LICENSE +21 -0
- focus_data_toolkit-0.11.0.dist-info/licenses/LICENSES/CC-BY-4.0.txt +156 -0
- focus_data_toolkit-0.11.0.dist-info/licenses/NOTICE +60 -0
- focus_data_toolkit-0.11.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://focus.finops.org/schemas/contractcommitmentapplicabilityobject.json",
|
|
4
|
+
"title": "Contract Commitment Applicability Object",
|
|
5
|
+
"description": "Schema for validating the Contract Commitment Applicability column JSON object structure in FOCUS datasets",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"$defs": {
|
|
8
|
+
"ApplicabilityObject": {
|
|
9
|
+
"type": "object",
|
|
10
|
+
"properties": {
|
|
11
|
+
"Cost": {
|
|
12
|
+
"type": "number",
|
|
13
|
+
"description": "Percentage applicable to ContractCommitmentCost",
|
|
14
|
+
"minimum": 0.0,
|
|
15
|
+
"maximum": 1.0,
|
|
16
|
+
"default": 1.0
|
|
17
|
+
},
|
|
18
|
+
"Usage": {
|
|
19
|
+
"type": "number",
|
|
20
|
+
"description": "Percentage applicable to ContractCommitmentQuantity",
|
|
21
|
+
"minimum": 0.0,
|
|
22
|
+
"maximum": 1.0,
|
|
23
|
+
"default": 1.0
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
"additionalProperties": false
|
|
27
|
+
},
|
|
28
|
+
"ApplicabilityRule": {
|
|
29
|
+
"type": "object",
|
|
30
|
+
"required": [
|
|
31
|
+
"Dimension",
|
|
32
|
+
"Operator",
|
|
33
|
+
"Values"
|
|
34
|
+
],
|
|
35
|
+
"properties": {
|
|
36
|
+
"Dimension": {
|
|
37
|
+
"type": "string",
|
|
38
|
+
"description": "A valid FOCUS Column Name"
|
|
39
|
+
},
|
|
40
|
+
"Operator": {
|
|
41
|
+
"type": "string",
|
|
42
|
+
"description": "The comparison logic to apply",
|
|
43
|
+
"enum": [
|
|
44
|
+
"In",
|
|
45
|
+
"NotIn",
|
|
46
|
+
"StartsWith",
|
|
47
|
+
"NotStartsWith",
|
|
48
|
+
"Contains",
|
|
49
|
+
"NotContains",
|
|
50
|
+
"EndsWith",
|
|
51
|
+
"Exists",
|
|
52
|
+
"DoesNotExist"
|
|
53
|
+
]
|
|
54
|
+
},
|
|
55
|
+
"Values": {
|
|
56
|
+
"type": "array",
|
|
57
|
+
"description": "List of strings to compare",
|
|
58
|
+
"items": {
|
|
59
|
+
"type": "string"
|
|
60
|
+
},
|
|
61
|
+
"minItems": 1
|
|
62
|
+
},
|
|
63
|
+
"Applicability": {
|
|
64
|
+
"$ref": "#/$defs/ApplicabilityObject",
|
|
65
|
+
"description": "Optional rule-level applicability that overrides top-level"
|
|
66
|
+
}
|
|
67
|
+
},
|
|
68
|
+
"allOf": [
|
|
69
|
+
{
|
|
70
|
+
"description": "Wildcard constraint: If '*' is used, it must be the only value and Operator must be compatible.",
|
|
71
|
+
"if": {
|
|
72
|
+
"properties": {
|
|
73
|
+
"Values": {
|
|
74
|
+
"contains": {
|
|
75
|
+
"const": "*"
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
"then": {
|
|
81
|
+
"properties": {
|
|
82
|
+
"Values": {
|
|
83
|
+
"maxItems": 1
|
|
84
|
+
},
|
|
85
|
+
"Operator": {
|
|
86
|
+
"enum": [
|
|
87
|
+
"In",
|
|
88
|
+
"Contains",
|
|
89
|
+
"Exists",
|
|
90
|
+
"DoesNotExist"
|
|
91
|
+
]
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
"description": "Existence Logic: Exists/DoesNotExist operators require the specific wildcard value.",
|
|
98
|
+
"if": {
|
|
99
|
+
"properties": {
|
|
100
|
+
"Operator": {
|
|
101
|
+
"enum": [
|
|
102
|
+
"Exists",
|
|
103
|
+
"DoesNotExist"
|
|
104
|
+
]
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
},
|
|
108
|
+
"then": {
|
|
109
|
+
"properties": {
|
|
110
|
+
"Values": {
|
|
111
|
+
"items": {
|
|
112
|
+
"const": "*"
|
|
113
|
+
},
|
|
114
|
+
"maxItems": 1
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
],
|
|
120
|
+
"additionalProperties": false
|
|
121
|
+
}
|
|
122
|
+
},
|
|
123
|
+
"properties": {
|
|
124
|
+
"IsGlobalScope": {
|
|
125
|
+
"type": "boolean",
|
|
126
|
+
"description": "If true, commitment applies to all entities",
|
|
127
|
+
"default": false
|
|
128
|
+
},
|
|
129
|
+
"IsComplexScope": {
|
|
130
|
+
"type": "boolean",
|
|
131
|
+
"description": "If true, applicability logic exceeds schema capabilities",
|
|
132
|
+
"default": false
|
|
133
|
+
},
|
|
134
|
+
"Applicability": {
|
|
135
|
+
"$ref": "#/$defs/ApplicabilityObject",
|
|
136
|
+
"description": "Top-level fractional mapping for metrics"
|
|
137
|
+
},
|
|
138
|
+
"InclusionOperator": {
|
|
139
|
+
"type": "string",
|
|
140
|
+
"description": "Logical operator for Inclusions array",
|
|
141
|
+
"enum": [
|
|
142
|
+
"And",
|
|
143
|
+
"Or"
|
|
144
|
+
]
|
|
145
|
+
},
|
|
146
|
+
"Inclusions": {
|
|
147
|
+
"type": "array",
|
|
148
|
+
"description": "List of rules defining the applicability boundary",
|
|
149
|
+
"items": {
|
|
150
|
+
"$ref": "#/$defs/ApplicabilityRule"
|
|
151
|
+
}
|
|
152
|
+
},
|
|
153
|
+
"ExclusionOperator": {
|
|
154
|
+
"type": "string",
|
|
155
|
+
"description": "Logical operator for Exclusions array",
|
|
156
|
+
"enum": [
|
|
157
|
+
"And",
|
|
158
|
+
"Or"
|
|
159
|
+
]
|
|
160
|
+
},
|
|
161
|
+
"Exclusions": {
|
|
162
|
+
"type": "array",
|
|
163
|
+
"description": "List of rules defining entities to exclude",
|
|
164
|
+
"items": {
|
|
165
|
+
"$ref": "#/$defs/ApplicabilityRule"
|
|
166
|
+
},
|
|
167
|
+
"minItems": 1
|
|
168
|
+
}
|
|
169
|
+
},
|
|
170
|
+
"allOf": [
|
|
171
|
+
{
|
|
172
|
+
"description": "IsGlobalScope and IsComplexScope cannot both be true simultaneously.",
|
|
173
|
+
"not": {
|
|
174
|
+
"required": [
|
|
175
|
+
"IsGlobalScope",
|
|
176
|
+
"IsComplexScope"
|
|
177
|
+
],
|
|
178
|
+
"properties": {
|
|
179
|
+
"IsGlobalScope": {
|
|
180
|
+
"const": true
|
|
181
|
+
},
|
|
182
|
+
"IsComplexScope": {
|
|
183
|
+
"const": true
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
},
|
|
188
|
+
{
|
|
189
|
+
"description": "If IsGlobalScope is true, Inclusions must be empty or omitted.",
|
|
190
|
+
"if": {
|
|
191
|
+
"properties": {
|
|
192
|
+
"IsGlobalScope": {
|
|
193
|
+
"const": true
|
|
194
|
+
}
|
|
195
|
+
},
|
|
196
|
+
"required": [
|
|
197
|
+
"IsGlobalScope"
|
|
198
|
+
]
|
|
199
|
+
},
|
|
200
|
+
"then": {
|
|
201
|
+
"properties": {
|
|
202
|
+
"Inclusions": {
|
|
203
|
+
"maxItems": 0
|
|
204
|
+
},
|
|
205
|
+
"InclusionOperator": false
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
},
|
|
209
|
+
{
|
|
210
|
+
"description": "If IsComplexScope is true, Inclusions must be empty or omitted.",
|
|
211
|
+
"if": {
|
|
212
|
+
"properties": {
|
|
213
|
+
"IsComplexScope": {
|
|
214
|
+
"const": true
|
|
215
|
+
}
|
|
216
|
+
},
|
|
217
|
+
"required": [
|
|
218
|
+
"IsComplexScope"
|
|
219
|
+
]
|
|
220
|
+
},
|
|
221
|
+
"then": {
|
|
222
|
+
"properties": {
|
|
223
|
+
"Inclusions": {
|
|
224
|
+
"maxItems": 0
|
|
225
|
+
},
|
|
226
|
+
"InclusionOperator": false
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
},
|
|
230
|
+
{
|
|
231
|
+
"description": "If neither Global nor Complex scope is active, Inclusions and InclusionOperator are required.",
|
|
232
|
+
"if": {
|
|
233
|
+
"not": {
|
|
234
|
+
"anyOf": [
|
|
235
|
+
{
|
|
236
|
+
"properties": {
|
|
237
|
+
"IsGlobalScope": {
|
|
238
|
+
"const": true
|
|
239
|
+
}
|
|
240
|
+
},
|
|
241
|
+
"required": [
|
|
242
|
+
"IsGlobalScope"
|
|
243
|
+
]
|
|
244
|
+
},
|
|
245
|
+
{
|
|
246
|
+
"properties": {
|
|
247
|
+
"IsComplexScope": {
|
|
248
|
+
"const": true
|
|
249
|
+
}
|
|
250
|
+
},
|
|
251
|
+
"required": [
|
|
252
|
+
"IsComplexScope"
|
|
253
|
+
]
|
|
254
|
+
}
|
|
255
|
+
]
|
|
256
|
+
}
|
|
257
|
+
},
|
|
258
|
+
"then": {
|
|
259
|
+
"required": [
|
|
260
|
+
"InclusionOperator",
|
|
261
|
+
"Inclusions"
|
|
262
|
+
],
|
|
263
|
+
"properties": {
|
|
264
|
+
"Inclusions": {
|
|
265
|
+
"minItems": 1
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
},
|
|
270
|
+
{
|
|
271
|
+
"description": "If Exclusions are present, ExclusionOperator is required.",
|
|
272
|
+
"if": {
|
|
273
|
+
"required": [
|
|
274
|
+
"Exclusions"
|
|
275
|
+
]
|
|
276
|
+
},
|
|
277
|
+
"then": {
|
|
278
|
+
"required": [
|
|
279
|
+
"ExclusionOperator"
|
|
280
|
+
]
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
],
|
|
284
|
+
"patternProperties": {
|
|
285
|
+
"^x_[A-Z][a-zA-Z0-9]*$": {
|
|
286
|
+
"description": "Custom data generator-defined properties prefixed with x_ in PascalCase format"
|
|
287
|
+
}
|
|
288
|
+
},
|
|
289
|
+
"additionalProperties": false
|
|
290
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"description": "Provenance of the vendored official FOCUS JSON object schemas.",
|
|
3
|
+
"source_repository": "https://github.com/FinOps-Open-Cost-and-Usage-Spec/FOCUS_Spec",
|
|
4
|
+
"source_ref": "v1.4",
|
|
5
|
+
"license": "CC-BY-4.0",
|
|
6
|
+
"attribution": "FinOps Open Cost and Usage Specification (FOCUS), (c) FinOps Foundation. Schemas vendored verbatim from the specification repository.",
|
|
7
|
+
"retrieved": "2026-07-17",
|
|
8
|
+
"files": [
|
|
9
|
+
{
|
|
10
|
+
"file": "contractappliedobjectschema.json",
|
|
11
|
+
"source_path": "specification/schemas/datasets/cost_and_usage/contractappliedobjectschema.json",
|
|
12
|
+
"column": "ContractApplied",
|
|
13
|
+
"sha256": "26ad380f89c12b414f36822fb4f12786e4eacfb0d00ac4781a84752483a5d73e",
|
|
14
|
+
"bytes": 4352
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"file": "allocatedmethoddetailsobjectschema.json",
|
|
18
|
+
"source_path": "specification/schemas/datasets/cost_and_usage/allocatedmethoddetailsobjectschema.json",
|
|
19
|
+
"column": "AllocatedMethodDetails",
|
|
20
|
+
"sha256": "0f552469954433c04a51ad18561e4b85e13787570cda4a4cc5a733a39214d8fd",
|
|
21
|
+
"bytes": 3250
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"file": "commitmentprogrameligibilitydetailsobjectschema.json",
|
|
25
|
+
"source_path": "specification/schemas/datasets/cost_and_usage/commitmentprogrameligibilitydetailsobjectschema.json",
|
|
26
|
+
"column": "CommitmentProgramEligibilityDetails",
|
|
27
|
+
"sha256": "0cc2fc4bfc3a720754591c017a5899d214f78d630167a16e99c2875cb91de576",
|
|
28
|
+
"bytes": 1647
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
"file": "contractcommitmentapplicabilityobjectschema.json",
|
|
32
|
+
"source_path": "specification/schemas/datasets/contract_commitment/contractcommitmentapplicabilityobjectschema.json",
|
|
33
|
+
"column": "ContractCommitmentApplicability",
|
|
34
|
+
"sha256": "6c396aa5ac0ccfed1bfb1c464d6698684520554aca50dca3258307ff779a565b",
|
|
35
|
+
"bytes": 7143
|
|
36
|
+
}
|
|
37
|
+
]
|
|
38
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://raw.githubusercontent.com/guymano/focus-data-toolkit/main/schema/model_provenance.schema.json",
|
|
3
|
+
"schema_version": "1.0",
|
|
4
|
+
"focus_version": "1.4",
|
|
5
|
+
"provenance_status": "complete",
|
|
6
|
+
"description": "Provenance for the committed FOCUS 1.4 machine-readable model (focus_1_4_model.json). The JSON is a deterministic extraction of the FinOps Foundation FOCUS 1.4 Data Model and is the artifact of record for this package.",
|
|
7
|
+
"source": {
|
|
8
|
+
"name": "FinOps FOCUS 1.4 Data Model workbook",
|
|
9
|
+
"publisher": "FinOps Foundation",
|
|
10
|
+
"homepage": "https://focus.finops.org",
|
|
11
|
+
"repository": "https://github.com/FinOps-Open-Cost-and-Usage-Spec/FOCUS_Spec",
|
|
12
|
+
"license": "CC-BY-4.0",
|
|
13
|
+
"license_verified": true,
|
|
14
|
+
"license_reference": "https://github.com/FinOps-Open-Cost-and-Usage-Spec/FOCUS_Spec/blob/main/license.md",
|
|
15
|
+
"artifact": "FOCUS 1.4 Data Model workbook (spreadsheet), downloaded from https://focus.finops.org; not redistributed in this repository",
|
|
16
|
+
"artifact_sha256": "39b3e3347e902a484cad180ead6fcb5a96b70cc76391c9af1916911a25a68005",
|
|
17
|
+
"artifact_retrieved": "2026-07-18"
|
|
18
|
+
},
|
|
19
|
+
"supplements": [
|
|
20
|
+
{
|
|
21
|
+
"path": "src/focus_data_toolkit/model/focus_1_4_servicesubcategory.json",
|
|
22
|
+
"sha256": "8532467093bedd1e228a82f07c782d8b29286de75d0a79bccbf896debd867f64",
|
|
23
|
+
"description": "ServiceSubcategory -> parent Category map, transcribed from the FOCUS v1.4 specification; an input to the extractor."
|
|
24
|
+
}
|
|
25
|
+
],
|
|
26
|
+
"generator": {
|
|
27
|
+
"script": "tools/extract_focus_1_4_model.py",
|
|
28
|
+
"script_sha256": "4fc4c8d6f30f3b3045c7f6afcc46b81ebbb44d800e63993246878374d4ee9403",
|
|
29
|
+
"command": "python tools/extract_focus_1_4_model.py <focus_1_4_data_model.xlsx>",
|
|
30
|
+
"runtime": "Dev-time only; requires openpyxl. Neither the runtime package nor the test suite imports openpyxl — the committed JSON is the artifact of record.",
|
|
31
|
+
"serialization": "json.dumps(model, indent=2, sort_keys=True) + trailing newline; UTF-8. Deterministic: identical (workbook, supplement, generator) reproduce identical output bytes."
|
|
32
|
+
},
|
|
33
|
+
"output": {
|
|
34
|
+
"path": "src/focus_data_toolkit/model/focus_1_4_model.json",
|
|
35
|
+
"sha256": "8b006e1a36bc9678fef6b79c847654f914ea7abe25c827478aa44ee1d15b214b",
|
|
36
|
+
"bytes": 64971,
|
|
37
|
+
"focus_version": "1.4",
|
|
38
|
+
"datasets": {
|
|
39
|
+
"Cost and Usage": 65,
|
|
40
|
+
"Billing Period": 6,
|
|
41
|
+
"Contract Commitment": 30,
|
|
42
|
+
"Invoice Detail": 22
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
"reproducibility": {
|
|
46
|
+
"byte_for_byte": "The committed output is byte-reproducible by re-running the pinned generator on the same source workbook: the serialization is deterministic (sorted keys, fixed indent, UTF-8, trailing newline).",
|
|
47
|
+
"verifiable_in_ci": [
|
|
48
|
+
"output.sha256 matches the committed focus_1_4_model.json",
|
|
49
|
+
"generator.script_sha256 matches the committed extractor",
|
|
50
|
+
"supplements[].sha256 match the committed supplement files"
|
|
51
|
+
],
|
|
52
|
+
"limitation": "None for the model chain: the source workbook is hashed (source.artifact_sha256) and the committed output was reproduced byte-for-byte from it by the pinned extractor at completion time. The workbook itself is still not redistributed; obtain it from the FinOps Foundation and verify it against source.artifact_sha256."
|
|
53
|
+
},
|
|
54
|
+
"attribution": "FOCUS(TM) is a trademark of the FinOps Foundation. The FOCUS specification and data model are (c) the FinOps Foundation and are licensed CC-BY-4.0. The committed model JSON and this provenance file are a derivative work distributed under CC-BY-4.0 with attribution. This project is an independent community toolkit and is not endorsed by the FinOps Foundation.",
|
|
55
|
+
"notes": [
|
|
56
|
+
"provenance_status was set to 'complete' by scripts/verify_model_provenance.py --complete: the source workbook was hashed and the committed model was reproduced byte-for-byte from it with the pinned extractor."
|
|
57
|
+
]
|
|
58
|
+
}
|