sort4circ-dpp 1.3.1__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.
Files changed (94) hide show
  1. sort4circ_dpp/__init__.py +30 -0
  2. sort4circ_dpp/_spec/access-matrix.json +145 -0
  3. sort4circ_dpp/_spec/reason-codes.json +232 -0
  4. sort4circ_dpp/_spec/schemas/dpp-1.0.0.schema.json +288 -0
  5. sort4circ_dpp/_spec/schemas/dpp-1.0.0.xsd +148 -0
  6. sort4circ_dpp/_spec/vocabularies/article-class.json +93 -0
  7. sort4circ_dpp/_spec/vocabularies/binding-status.json +33 -0
  8. sort4circ_dpp/_spec/vocabularies/carrier-type.json +33 -0
  9. sort4circ_dpp/_spec/vocabularies/colour-family.json +51 -0
  10. sort4circ_dpp/_spec/vocabularies/component-type.json +75 -0
  11. sort4circ_dpp/_spec/vocabularies/condition.json +45 -0
  12. sort4circ_dpp/_spec/vocabularies/confidence-scale.json +21 -0
  13. sort4circ_dpp/_spec/vocabularies/encoding-scheme.json +33 -0
  14. sort4circ_dpp/_spec/vocabularies/event-type.json +87 -0
  15. sort4circ_dpp/_spec/vocabularies/evidence-state.json +45 -0
  16. sort4circ_dpp/_spec/vocabularies/fabric-construction.json +51 -0
  17. sort4circ_dpp/_spec/vocabularies/fibre-type.json +194 -0
  18. sort4circ_dpp/_spec/vocabularies/method.json +65 -0
  19. sort4circ_dpp/_spec/vocabularies/passport-status.json +33 -0
  20. sort4circ_dpp/_spec/vocabularies/percentage-basis.json +21 -0
  21. sort4circ_dpp/_spec/vocabularies/sorting-category.json +69 -0
  22. sort4circ_dpp/_spec/vocabularies/technical-flag.json +93 -0
  23. sort4circ_dpp/_spec/vocabularies/value-status.json +39 -0
  24. sort4circ_dpp/access.py +210 -0
  25. sort4circ_dpp/api.py +435 -0
  26. sort4circ_dpp/auth.py +38 -0
  27. sort4circ_dpp/canonical.py +141 -0
  28. sort4circ_dpp/cli.py +41 -0
  29. sort4circ_dpp/config.py +76 -0
  30. sort4circ_dpp/evidence.py +137 -0
  31. sort4circ_dpp/exchange.py +286 -0
  32. sort4circ_dpp/gateway/__init__.py +5 -0
  33. sort4circ_dpp/gateway/readzone.py +89 -0
  34. sort4circ_dpp/governance.py +77 -0
  35. sort4circ_dpp/index.py +146 -0
  36. sort4circ_dpp/ledger/__init__.py +11 -0
  37. sort4circ_dpp/ledger/base.py +78 -0
  38. sort4circ_dpp/ledger/besu.py +136 -0
  39. sort4circ_dpp/ledger/memory.py +77 -0
  40. sort4circ_dpp/mapping.py +177 -0
  41. sort4circ_dpp/public_summary.py +53 -0
  42. sort4circ_dpp/py.typed +0 -0
  43. sort4circ_dpp/reasons.py +112 -0
  44. sort4circ_dpp/spec/access-matrix.json +145 -0
  45. sort4circ_dpp/spec/governance/en18223-deviation-open-template.json +21 -0
  46. sort4circ_dpp/spec/governance/en18223-deviation.schema.json +70 -0
  47. sort4circ_dpp/spec/governance/environmental-selection-template.json +30 -0
  48. sort4circ_dpp/spec/governance/environmental-selection.schema.json +72 -0
  49. sort4circ_dpp/spec/mappings/README.md +46 -0
  50. sort4circ_dpp/spec/mappings/dpp-mapping-1.0.0.csv +125 -0
  51. sort4circ_dpp/spec/mappings/dpp-mapping-1.0.0.json +2370 -0
  52. sort4circ_dpp/spec/mappings/dpp-mapping-1.0.0.schema.json +93 -0
  53. sort4circ_dpp/spec/ontology/sort4circ-1.0.1.ttl +372 -0
  54. sort4circ_dpp/spec/openapi/dpp-api-v1.json +782 -0
  55. sort4circ_dpp/spec/queries/environmental-values-1.0.0.rq +2 -0
  56. sort4circ_dpp/spec/queries/expected-results-1.0.0.json +10 -0
  57. sort4circ_dpp/spec/queries/identity-resolution-1.0.0.rq +7 -0
  58. sort4circ_dpp/spec/queries/lifecycle-events-1.0.0.rq +2 -0
  59. sort4circ_dpp/spec/queries/material-divergence-1.0.0.rq +12 -0
  60. sort4circ_dpp/spec/queries/product-hierarchy-1.0.0.rq +2 -0
  61. sort4circ_dpp/spec/queries/sorting-results-1.0.0.rq +2 -0
  62. sort4circ_dpp/spec/reason-codes.json +232 -0
  63. sort4circ_dpp/spec/schemas/dpp-1.0.0.schema.json +288 -0
  64. sort4circ_dpp/spec/schemas/dpp-1.0.0.xsd +148 -0
  65. sort4circ_dpp/spec/vocabularies/article-class.json +93 -0
  66. sort4circ_dpp/spec/vocabularies/binding-status.json +33 -0
  67. sort4circ_dpp/spec/vocabularies/carrier-type.json +33 -0
  68. sort4circ_dpp/spec/vocabularies/colour-family.json +51 -0
  69. sort4circ_dpp/spec/vocabularies/component-type.json +75 -0
  70. sort4circ_dpp/spec/vocabularies/condition.json +45 -0
  71. sort4circ_dpp/spec/vocabularies/confidence-scale.json +21 -0
  72. sort4circ_dpp/spec/vocabularies/encoding-scheme.json +33 -0
  73. sort4circ_dpp/spec/vocabularies/event-type.json +87 -0
  74. sort4circ_dpp/spec/vocabularies/evidence-state.json +45 -0
  75. sort4circ_dpp/spec/vocabularies/fabric-construction.json +51 -0
  76. sort4circ_dpp/spec/vocabularies/fibre-type.json +194 -0
  77. sort4circ_dpp/spec/vocabularies/method.json +65 -0
  78. sort4circ_dpp/spec/vocabularies/passport-status.json +33 -0
  79. sort4circ_dpp/spec/vocabularies/percentage-basis.json +21 -0
  80. sort4circ_dpp/spec/vocabularies/sorting-category.json +69 -0
  81. sort4circ_dpp/spec/vocabularies/technical-flag.json +93 -0
  82. sort4circ_dpp/spec/vocabularies/value-status.json +39 -0
  83. sort4circ_dpp/store.py +365 -0
  84. sort4circ_dpp/synthetic.py +154 -0
  85. sort4circ_dpp/validation.py +112 -0
  86. sort4circ_dpp/vocab.py +151 -0
  87. sort4circ_dpp-1.3.1.dist-info/METADATA +276 -0
  88. sort4circ_dpp-1.3.1.dist-info/RECORD +94 -0
  89. sort4circ_dpp-1.3.1.dist-info/WHEEL +5 -0
  90. sort4circ_dpp-1.3.1.dist-info/entry_points.txt +2 -0
  91. sort4circ_dpp-1.3.1.dist-info/licenses/LICENSE +202 -0
  92. sort4circ_dpp-1.3.1.dist-info/licenses/LICENSE-DOCS +47 -0
  93. sort4circ_dpp-1.3.1.dist-info/licenses/LICENSING.md +90 -0
  94. sort4circ_dpp-1.3.1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,30 @@
1
+ """Reference implementation of the SORT4CIRC DPP implementation profile.
2
+
3
+ Two version numbers matter here and they are not the same thing:
4
+
5
+ ``__version__``
6
+ the version of this repository, package and GitHub release.
7
+ ``sort4circ_dpp.config.PROFILE_VERSION``
8
+ the version of the normative DPP implementation profile this code implements.
9
+ Individual specification assets are versioned per asset; see ``config``.
10
+
11
+ Normative requirements apply only within that published profile. The specification
12
+ originates in SORT4CIRC deliverable D4.3, "DPP Development Guidelines".
13
+ """
14
+
15
+ from .canonical import canonicalise, digest, integrity_projection
16
+ from .config import API_MAJOR, ONTOLOGY_VERSION, PROFILE_VERSION, RELEASE_VERSION, SCHEMA_VERSION
17
+
18
+ #: Repository / package / release version. Not the normative profile version.
19
+ __version__ = RELEASE_VERSION
20
+
21
+ __all__ = [
22
+ "canonicalise",
23
+ "digest",
24
+ "integrity_projection",
25
+ "PROFILE_VERSION",
26
+ "SCHEMA_VERSION",
27
+ "ONTOLOGY_VERSION",
28
+ "API_MAJOR",
29
+ "__version__",
30
+ ]
@@ -0,0 +1,145 @@
1
+ {
2
+ "$id": "https://data.sort4circ.eu/access-matrix/1.0.0",
3
+ "version": "1.0.0",
4
+ "released": "2026-08-10",
5
+ "policy": "defaultDeny",
6
+ "note": "Holding a scope is necessary and not sufficient. The view determines what the caller receives. A field the caller may know exists but not read is returned with valueStatus withheld.",
7
+ "roles": {
8
+ "public": {
9
+ "scopes": [
10
+ "dpp.read"
11
+ ],
12
+ "defaultView": "public"
13
+ },
14
+ "consumer": {
15
+ "scopes": [
16
+ "dpp.read"
17
+ ],
18
+ "defaultView": "public"
19
+ },
20
+ "brand": {
21
+ "scopes": [
22
+ "dpp.read",
23
+ "dpp.write",
24
+ "dpp.event",
25
+ "dpp.resolve",
26
+ "observation.write",
27
+ "integrity.read"
28
+ ],
29
+ "defaultView": "full"
30
+ },
31
+ "collector": {
32
+ "scopes": [
33
+ "dpp.read",
34
+ "dpp.event",
35
+ "dpp.resolve"
36
+ ],
37
+ "defaultView": "partner"
38
+ },
39
+ "sortingOperator": {
40
+ "scopes": [
41
+ "dpp.read",
42
+ "dpp.event",
43
+ "dpp.resolve",
44
+ "sorting.read"
45
+ ],
46
+ "defaultView": "sorting"
47
+ },
48
+ "pssrSystem": {
49
+ "scopes": [
50
+ "dpp.read",
51
+ "dpp.resolve",
52
+ "sorting.read",
53
+ "observation.write",
54
+ "dpp.event"
55
+ ],
56
+ "defaultView": "sorting"
57
+ },
58
+ "recycler": {
59
+ "scopes": [
60
+ "dpp.read",
61
+ "dpp.event",
62
+ "dpp.resolve"
63
+ ],
64
+ "defaultView": "recycler"
65
+ },
66
+ "authority": {
67
+ "scopes": [
68
+ "dpp.read",
69
+ "integrity.read",
70
+ "integrity.verify"
71
+ ],
72
+ "defaultView": "authority"
73
+ },
74
+ "administrator": {
75
+ "scopes": [
76
+ "dpp.read",
77
+ "dpp.write",
78
+ "dpp.event",
79
+ "dpp.resolve",
80
+ "sorting.read",
81
+ "observation.write",
82
+ "integrity.read",
83
+ "integrity.verify",
84
+ "admin"
85
+ ],
86
+ "defaultView": "full"
87
+ },
88
+ "integrityVerifier": {
89
+ "scopes": [
90
+ "dpp.read",
91
+ "integrity.read",
92
+ "integrity.verify"
93
+ ],
94
+ "defaultView": "integrityOnly"
95
+ }
96
+ },
97
+ "views": {
98
+ "public": [
99
+ "dppId",
100
+ "schemaVersion",
101
+ "recordVersion",
102
+ "status",
103
+ "identity.granularity",
104
+ "product.articleClass",
105
+ "product.fabricConstruction",
106
+ "product.technicalFlags",
107
+ "materialObservations"
108
+ ],
109
+ "partner": [
110
+ "public",
111
+ "identity.modelId",
112
+ "identity.batchId",
113
+ "lifecycleEvents.own"
114
+ ],
115
+ "sorting": [
116
+ "public",
117
+ "identity.itemId",
118
+ "identity.epc",
119
+ "product.colourPrimary",
120
+ "product.condition",
121
+ "sortingDecisions",
122
+ "carriers.active"
123
+ ],
124
+ "recycler": [
125
+ "sorting",
126
+ "components",
127
+ "product.mass"
128
+ ],
129
+ "authority": [
130
+ "sorting",
131
+ "recycler",
132
+ "lifecycleEvents",
133
+ "integrity",
134
+ "identity",
135
+ "carriers"
136
+ ],
137
+ "full": [
138
+ "*"
139
+ ],
140
+ "integrityOnly": [
141
+ "dppId",
142
+ "integrity"
143
+ ]
144
+ }
145
+ }
@@ -0,0 +1,232 @@
1
+ {
2
+ "$id": "https://data.sort4circ.eu/reason-codes/1.0.0",
3
+ "version": "1.0.0",
4
+ "released": "2026-08-10",
5
+ "note": "Reason codes are stable strings. A released code is never reworded or renumbered. Clients dispatch on the code, not on the title.",
6
+ "safeActions": {
7
+ "divert": "Route to the manual-review destination; engage no category-specific actuator.",
8
+ "divertAndAlert": "Divert and raise an operational alert.",
9
+ "retryOnceThenDivert": "One re-attempt after credential refresh, then divert.",
10
+ "noCommand": "Emit no new sorting command. Not an error.",
11
+ "rejectAtClient": "Not on the read path; the client corrects the request.",
12
+ "quarantine": "Hold the source row for operator review; never discard it.",
13
+ "noEffectOnSorting": "Sorting continues; evidence remains queued.",
14
+ "retrySameEvidenceId": "Retry using the same evidence identifier and digest.",
15
+ "reconcileBeforeResubmit": "Reconcile by evidence identifier before creating another transaction.",
16
+ "investigate": "A verification verdict, not an error response.",
17
+ "backOff": "Back off using the Retry-After header.",
18
+ "rereadAndReapply": "Re-read the current version and reapply the change. Never force the write."
19
+ },
20
+ "codes": [
21
+ {
22
+ "code": "S4C-IDENT-MALFORMED",
23
+ "httpStatus": 400,
24
+ "condition": "Identifier fails syntax or check-digit validation.",
25
+ "safeAction": "divert",
26
+ "type": "https://data.sort4circ.eu/problems/s4c-ident-malformed"
27
+ },
28
+ {
29
+ "code": "S4C-IDENT-UNKNOWN",
30
+ "httpStatus": 404,
31
+ "condition": "Well-formed identifier with no passport.",
32
+ "safeAction": "divert",
33
+ "type": "https://data.sort4circ.eu/problems/s4c-ident-unknown"
34
+ },
35
+ {
36
+ "code": "S4C-IDENT-RETIRED",
37
+ "httpStatus": 410,
38
+ "condition": "Passport retired; successor returned where present.",
39
+ "safeAction": "divert",
40
+ "type": "https://data.sort4circ.eu/problems/s4c-ident-retired"
41
+ },
42
+ {
43
+ "code": "S4C-IDENT-AMBIGUOUS",
44
+ "httpStatus": 409,
45
+ "condition": "More than one tag read within the zone window.",
46
+ "safeAction": "divert",
47
+ "type": "https://data.sort4circ.eu/problems/s4c-ident-ambiguous"
48
+ },
49
+ {
50
+ "code": "S4C-IDENT-DUPLICATE-BINDING",
51
+ "httpStatus": 409,
52
+ "condition": "One identifier resolves to two active passports.",
53
+ "safeAction": "divertAndAlert",
54
+ "type": "https://data.sort4circ.eu/problems/s4c-ident-duplicate-binding"
55
+ },
56
+ {
57
+ "code": "S4C-READ-SUPPRESSED-DUPLICATE",
58
+ "httpStatus": 200,
59
+ "condition": "Repeat read inside the suppression window.",
60
+ "safeAction": "noCommand",
61
+ "type": "https://data.sort4circ.eu/problems/s4c-read-suppressed-duplicate"
62
+ },
63
+ {
64
+ "code": "S4C-READ-WEAK-SIGNAL",
65
+ "httpStatus": 200,
66
+ "condition": "Read below the configured confidence floor.",
67
+ "safeAction": "divert",
68
+ "type": "https://data.sort4circ.eu/problems/s4c-read-weak-signal"
69
+ },
70
+ {
71
+ "code": "S4C-AUTH-MISSING-TOKEN",
72
+ "httpStatus": 401,
73
+ "condition": "No credential presented.",
74
+ "safeAction": "divertAndAlert",
75
+ "type": "https://data.sort4circ.eu/problems/s4c-auth-missing-token"
76
+ },
77
+ {
78
+ "code": "S4C-AUTH-INVALID-TOKEN",
79
+ "httpStatus": 401,
80
+ "condition": "Signature, issuer or audience invalid.",
81
+ "safeAction": "divertAndAlert",
82
+ "type": "https://data.sort4circ.eu/problems/s4c-auth-invalid-token"
83
+ },
84
+ {
85
+ "code": "S4C-AUTH-EXPIRED-TOKEN",
86
+ "httpStatus": 401,
87
+ "condition": "Token outside the stated validity window.",
88
+ "safeAction": "retryOnceThenDivert",
89
+ "type": "https://data.sort4circ.eu/problems/s4c-auth-expired-token"
90
+ },
91
+ {
92
+ "code": "S4C-AUTHZ-OPERATION-FORBIDDEN",
93
+ "httpStatus": 403,
94
+ "condition": "Caller lacks the required scope.",
95
+ "safeAction": "divertAndAlert",
96
+ "type": "https://data.sort4circ.eu/problems/s4c-authz-operation-forbidden"
97
+ },
98
+ {
99
+ "code": "S4C-AUTHZ-VIEW-FORBIDDEN",
100
+ "httpStatus": 403,
101
+ "condition": "Caller may not receive the requested view.",
102
+ "safeAction": "divertAndAlert",
103
+ "type": "https://data.sort4circ.eu/problems/s4c-authz-view-forbidden"
104
+ },
105
+ {
106
+ "code": "S4C-PAYLOAD-SCHEMA-INVALID",
107
+ "httpStatus": 422,
108
+ "condition": "Body fails schema validation; failing paths returned.",
109
+ "safeAction": "rejectAtClient",
110
+ "type": "https://data.sort4circ.eu/problems/s4c-payload-schema-invalid"
111
+ },
112
+ {
113
+ "code": "S4C-PAYLOAD-VOCAB-INVALID",
114
+ "httpStatus": 422,
115
+ "condition": "Coded value outside the declared vocabulary version.",
116
+ "safeAction": "rejectAtClient",
117
+ "type": "https://data.sort4circ.eu/problems/s4c-payload-vocab-invalid"
118
+ },
119
+ {
120
+ "code": "S4C-PAYLOAD-UNIT-INVALID",
121
+ "httpStatus": 422,
122
+ "condition": "Unit missing or not permitted for the quantity.",
123
+ "safeAction": "rejectAtClient",
124
+ "type": "https://data.sort4circ.eu/problems/s4c-payload-unit-invalid"
125
+ },
126
+ {
127
+ "code": "S4C-PAYLOAD-VERSION-UNSUPPORTED",
128
+ "httpStatus": 400,
129
+ "condition": "Schema version not served.",
130
+ "safeAction": "rejectAtClient",
131
+ "type": "https://data.sort4circ.eu/problems/s4c-payload-version-unsupported"
132
+ },
133
+ {
134
+ "code": "S4C-STATE-VERSION-CONFLICT",
135
+ "httpStatus": 412,
136
+ "condition": "If-Match does not equal the current record version.",
137
+ "safeAction": "rereadAndReapply",
138
+ "type": "https://data.sort4circ.eu/problems/s4c-state-version-conflict"
139
+ },
140
+ {
141
+ "code": "S4C-STATE-IDEMPOTENCY-CONFLICT",
142
+ "httpStatus": 409,
143
+ "condition": "Same idempotency key, different request body.",
144
+ "safeAction": "rejectAtClient",
145
+ "type": "https://data.sort4circ.eu/problems/s4c-state-idempotency-conflict"
146
+ },
147
+ {
148
+ "code": "S4C-STATE-APPEND-ONLY-VIOLATION",
149
+ "httpStatus": 422,
150
+ "condition": "Attempt to remove an append-only entry.",
151
+ "safeAction": "rejectAtClient",
152
+ "type": "https://data.sort4circ.eu/problems/s4c-state-append-only-violation"
153
+ },
154
+ {
155
+ "code": "S4C-STATE-NOT-FOUND",
156
+ "httpStatus": 404,
157
+ "condition": "The addressed resource does not exist.",
158
+ "safeAction": "rejectAtClient",
159
+ "type": "https://data.sort4circ.eu/problems/s4c-state-not-found"
160
+ },
161
+ {
162
+ "code": "S4C-MAP-NO-TARGET-RULE",
163
+ "httpStatus": 422,
164
+ "condition": "Source field has no approved mapping.",
165
+ "safeAction": "quarantine",
166
+ "type": "https://data.sort4circ.eu/problems/s4c-map-no-target-rule"
167
+ },
168
+ {
169
+ "code": "S4C-MAP-UNIT-CONVERSION-FAILED",
170
+ "httpStatus": 422,
171
+ "condition": "Conversion undefined or out of range.",
172
+ "safeAction": "quarantine",
173
+ "type": "https://data.sort4circ.eu/problems/s4c-map-unit-conversion-failed"
174
+ },
175
+ {
176
+ "code": "S4C-MAP-VOCAB-UNMAPPED",
177
+ "httpStatus": 422,
178
+ "condition": "Source term absent from the mapping table.",
179
+ "safeAction": "quarantine",
180
+ "type": "https://data.sort4circ.eu/problems/s4c-map-vocab-unmapped"
181
+ },
182
+ {
183
+ "code": "S4C-LEDGER-UNAVAILABLE",
184
+ "httpStatus": 503,
185
+ "condition": "Ledger endpoint unreachable.",
186
+ "safeAction": "noEffectOnSorting",
187
+ "type": "https://data.sort4circ.eu/problems/s4c-ledger-unavailable"
188
+ },
189
+ {
190
+ "code": "S4C-LEDGER-SUBMIT-REJECTED",
191
+ "httpStatus": 502,
192
+ "condition": "Transaction rejected by the network.",
193
+ "safeAction": "retrySameEvidenceId",
194
+ "type": "https://data.sort4circ.eu/problems/s4c-ledger-submit-rejected"
195
+ },
196
+ {
197
+ "code": "S4C-LEDGER-TIMEOUT-AFTER-BROADCAST",
198
+ "httpStatus": 504,
199
+ "condition": "Outcome unknown after broadcast.",
200
+ "safeAction": "reconcileBeforeResubmit",
201
+ "type": "https://data.sort4circ.eu/problems/s4c-ledger-timeout-after-broadcast"
202
+ },
203
+ {
204
+ "code": "S4C-LEDGER-DIGEST-MISMATCH",
205
+ "httpStatus": 200,
206
+ "condition": "Recomputed digest differs from the anchored value.",
207
+ "safeAction": "investigate",
208
+ "type": "https://data.sort4circ.eu/problems/s4c-ledger-digest-mismatch"
209
+ },
210
+ {
211
+ "code": "S4C-DEP-UNAVAILABLE",
212
+ "httpStatus": 503,
213
+ "condition": "A dependency needed for the operation is unavailable.",
214
+ "safeAction": "divert",
215
+ "type": "https://data.sort4circ.eu/problems/s4c-dep-unavailable"
216
+ },
217
+ {
218
+ "code": "S4C-RATE-LIMITED",
219
+ "httpStatus": 429,
220
+ "condition": "Caller exceeded the applicable quota.",
221
+ "safeAction": "backOff",
222
+ "type": "https://data.sort4circ.eu/problems/s4c-rate-limited"
223
+ },
224
+ {
225
+ "code": "S4C-INTERNAL-ERROR",
226
+ "httpStatus": 500,
227
+ "condition": "Unclassified server fault.",
228
+ "safeAction": "divertAndAlert",
229
+ "type": "https://data.sort4circ.eu/problems/s4c-internal-error"
230
+ }
231
+ ]
232
+ }