ssot-core 0.2.17.dev1__tar.gz → 0.2.18.dev9__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 (124) hide show
  1. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/PKG-INFO +10 -4
  2. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/README.md +4 -0
  3. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/pyproject.toml +6 -4
  4. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_core.egg-info/PKG-INFO +10 -4
  5. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_core.egg-info/SOURCES.txt +7 -0
  6. ssot_core-0.2.18.dev9/src/ssot_core.egg-info/requires.txt +7 -0
  7. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/api/__init__.py +25 -0
  8. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/api/claims.py +22 -3
  9. ssot_core-0.2.18.dev9/src/ssot_registry/api/config.py +283 -0
  10. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/api/documents.py +103 -10
  11. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/api/entity_ops.py +102 -12
  12. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/api/init.py +3 -0
  13. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/api/lifecycle.py +3 -0
  14. ssot_core-0.2.18.dev9/src/ssot_registry/api/local_assurance.py +234 -0
  15. ssot_core-0.2.18.dev9/src/ssot_registry/api/origin.py +98 -0
  16. ssot_core-0.2.18.dev9/src/ssot_registry/api/packs.py +486 -0
  17. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/api/plan.py +6 -0
  18. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/api/status_sync.py +40 -16
  19. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/api/test_execution.py +1 -0
  20. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/api/upgrade.py +78 -5
  21. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/api/validate.py +4 -0
  22. ssot_core-0.2.18.dev9/src/ssot_registry/guards/__init__.py +53 -0
  23. ssot_core-0.2.18.dev9/src/ssot_registry/guards/claim_tier_gates.py +317 -0
  24. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/model/claim.py +2 -0
  25. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/model/document.py +35 -0
  26. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/model/enums.py +20 -4
  27. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/model/evidence.py +1 -0
  28. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/model/feature.py +1 -0
  29. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/model/schema_version.py +1 -1
  30. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/model/test.py +1 -0
  31. ssot_core-0.2.18.dev9/src/ssot_registry/templates/registry.full.json +1 -0
  32. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/templates/registry.minimal.json +1 -1
  33. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/util/document_io.py +8 -4
  34. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/validators/__init__.py +4 -0
  35. ssot_core-0.2.18.dev9/src/ssot_registry/validators/claim_lineage.py +27 -0
  36. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/validators/documents.py +26 -2
  37. ssot_core-0.2.18.dev9/src/ssot_registry/validators/origin.py +31 -0
  38. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/validators/structure.py +50 -1
  39. ssot_core-0.2.17.dev1/src/ssot_core.egg-info/requires.txt +0 -6
  40. ssot_core-0.2.17.dev1/src/ssot_registry/guards/__init__.py +0 -23
  41. ssot_core-0.2.17.dev1/src/ssot_registry/templates/registry.full.json +0 -1
  42. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/setup.cfg +0 -0
  43. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_core.egg-info/dependency_links.txt +0 -0
  44. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_core.egg-info/top_level.txt +0 -0
  45. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/__init__.py +0 -0
  46. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/__main__.py +0 -0
  47. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/api/boundary.py +0 -0
  48. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/api/evidence.py +0 -0
  49. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/api/graph.py +0 -0
  50. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/api/load.py +0 -0
  51. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/api/profile_eval.py +0 -0
  52. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/api/profile_resolution.py +0 -0
  53. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/api/registry.py +0 -0
  54. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/api/release.py +0 -0
  55. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/api/save.py +0 -0
  56. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/cli/__init__.py +0 -0
  57. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/cli/adr_cmd.py +0 -0
  58. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/cli/boundary_cmd.py +0 -0
  59. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/cli/claim_cmd.py +0 -0
  60. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/cli/common.py +0 -0
  61. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/cli/evidence_cmd.py +0 -0
  62. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/cli/feature_cmd.py +0 -0
  63. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/cli/graph_cmd.py +0 -0
  64. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/cli/init_cmd.py +0 -0
  65. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/cli/issue_cmd.py +0 -0
  66. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/cli/main.py +0 -0
  67. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/cli/profile_cmd.py +0 -0
  68. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/cli/registry_cmd.py +0 -0
  69. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/cli/release_cmd.py +0 -0
  70. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/cli/risk_cmd.py +0 -0
  71. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/cli/spec_cmd.py +0 -0
  72. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/cli/test_cmd.py +0 -0
  73. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/cli/upgrade_cmd.py +0 -0
  74. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/cli/validate_cmd.py +0 -0
  75. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/graph/__init__.py +0 -0
  76. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/graph/export_dot.py +0 -0
  77. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/graph/export_json.py +0 -0
  78. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/guards/certification.py +0 -0
  79. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/guards/claim_closure.py +0 -0
  80. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/guards/document_lifecycle.py +0 -0
  81. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/guards/document_supersession.py +0 -0
  82. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/guards/feature_claims.py +0 -0
  83. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/guards/feature_requirements.py +0 -0
  84. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/guards/lifecycle.py +0 -0
  85. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/guards/profile_requirements.py +0 -0
  86. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/guards/promotion.py +0 -0
  87. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/guards/publication.py +0 -0
  88. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/model/__init__.py +0 -0
  89. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/model/boundary.py +0 -0
  90. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/model/ids.py +0 -0
  91. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/model/issue.py +0 -0
  92. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/model/profile.py +0 -0
  93. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/model/registry.py +0 -0
  94. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/model/release.py +0 -0
  95. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/model/risk.py +0 -0
  96. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/reports/__init__.py +0 -0
  97. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/reports/certification_report.py +0 -0
  98. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/reports/summary.py +0 -0
  99. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/reports/validation_report.py +0 -0
  100. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/snapshots/__init__.py +0 -0
  101. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/snapshots/boundary_snapshot.py +0 -0
  102. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/snapshots/hashing.py +0 -0
  103. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/snapshots/published_snapshot.py +0 -0
  104. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/snapshots/release_snapshot.py +0 -0
  105. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/templates/__init__.py +0 -0
  106. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/util/__init__.py +0 -0
  107. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/util/errors.py +0 -0
  108. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/util/formatting.py +0 -0
  109. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/util/fs.py +0 -0
  110. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/util/jcs.py +0 -0
  111. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/util/jsonio.py +0 -0
  112. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/util/registry_lock.py +0 -0
  113. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/util/time.py +0 -0
  114. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/validators/bidirectional.py +0 -0
  115. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/validators/bounds.py +0 -0
  116. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/validators/coverage.py +0 -0
  117. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/validators/filesystem.py +0 -0
  118. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/validators/identity.py +0 -0
  119. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/validators/lifecycle.py +0 -0
  120. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/validators/promotion.py +0 -0
  121. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/validators/references.py +0 -0
  122. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/validators/reservations.py +0 -0
  123. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/validators/tiers.py +0 -0
  124. {ssot_core-0.2.17.dev1 → ssot_core-0.2.18.dev9}/src/ssot_registry/version.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ssot-core
3
- Version: 0.2.17.dev1
3
+ Version: 0.2.18.dev9
4
4
  Summary: Core Python runtime, registry model, validation, and release workflow APIs for SSOT.
5
5
  Author-email: Jacob Stewart <jacob@swarmauri.com>
6
6
  License-Expression: Apache-2.0
@@ -21,6 +21,7 @@ Classifier: Programming Language :: Python :: 3.10
21
21
  Classifier: Programming Language :: Python :: 3.11
22
22
  Classifier: Programming Language :: Python :: 3.12
23
23
  Classifier: Programming Language :: Python :: 3.13
24
+ Classifier: Programming Language :: Python :: 3.14
24
25
  Classifier: Topic :: Database
25
26
  Classifier: Topic :: File Formats :: JSON
26
27
  Classifier: Topic :: File Formats :: JSON :: JSON Schema
@@ -32,11 +33,12 @@ Classifier: Topic :: Software Development :: Quality Assurance
32
33
  Classifier: Topic :: Software Development :: Testing
33
34
  Classifier: Topic :: System :: Archiving
34
35
  Classifier: Topic :: Utilities
35
- Requires-Python: <3.14,>=3.10
36
+ Requires-Python: <3.15,>=3.10
36
37
  Description-Content-Type: text/markdown
37
38
  Requires-Dist: orjson<4.0,>=3.10
38
- Requires-Dist: ssot-contracts==0.2.17.dev1
39
- Requires-Dist: ssot-views==0.2.17.dev1
39
+ Requires-Dist: ssot-contracts==0.2.18.dev9
40
+ Requires-Dist: ssot-pack-contracts<0.3.0,>=0.2.17
41
+ Requires-Dist: ssot-views==0.2.18.dev9
40
42
  Requires-Dist: tomli>=2.0.1; python_version < "3.11"
41
43
 
42
44
  <div align="center">
@@ -49,6 +51,10 @@ Requires-Dist: tomli>=2.0.1; python_version < "3.11"
49
51
  <a href="https://pypi.org/project/ssot-core/"><img src="https://img.shields.io/pypi/pyversions/ssot-core?label=Python" alt="Supported Python versions" /></a>
50
52
  <a href="https://pepy.tech/project/ssot-core"><img src="https://static.pepy.tech/badge/ssot-core" alt="Downloads" /></a>
51
53
  <a href="https://hits.sh/github.com/groupsum/ssot-registry/"><img src="https://hits.sh/github.com/groupsum/ssot-registry.svg?style=flat-square" alt="Hits" /></a>
54
+ <!-- ssot-schema-badges:start -->
55
+ <img src="https://img.shields.io/badge/schema_version-0.5.0-blue" alt="schema_version 0.5.0" />
56
+ <img src="https://img.shields.io/badge/migration%20coverage-12%2F12-brightgreen" alt="Migration coverage 12/12" />
57
+ <!-- ssot-schema-badges:end -->
52
58
  </div>
53
59
 
54
60
  `ssot-core` is the core Python runtime package for SSOT.
@@ -8,6 +8,10 @@
8
8
  <a href="https://pypi.org/project/ssot-core/"><img src="https://img.shields.io/pypi/pyversions/ssot-core?label=Python" alt="Supported Python versions" /></a>
9
9
  <a href="https://pepy.tech/project/ssot-core"><img src="https://static.pepy.tech/badge/ssot-core" alt="Downloads" /></a>
10
10
  <a href="https://hits.sh/github.com/groupsum/ssot-registry/"><img src="https://hits.sh/github.com/groupsum/ssot-registry.svg?style=flat-square" alt="Hits" /></a>
11
+ <!-- ssot-schema-badges:start -->
12
+ <img src="https://img.shields.io/badge/schema_version-0.5.0-blue" alt="schema_version 0.5.0" />
13
+ <img src="https://img.shields.io/badge/migration%20coverage-12%2F12-brightgreen" alt="Migration coverage 12/12" />
14
+ <!-- ssot-schema-badges:end -->
11
15
  </div>
12
16
 
13
17
  `ssot-core` is the core Python runtime package for SSOT.
@@ -4,16 +4,17 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "ssot-core"
7
- version = "0.2.17.dev1"
7
+ version = "0.2.18.dev9"
8
8
  description = "Core Python runtime, registry model, validation, and release workflow APIs for SSOT."
9
9
  readme = "README.md"
10
- requires-python = ">=3.10,<3.14"
10
+ requires-python = ">=3.10,<3.15"
11
11
  license = "Apache-2.0"
12
12
  authors = [{ name = "Jacob Stewart", email = "jacob@swarmauri.com" }]
13
13
  dependencies = [
14
14
  "orjson>=3.10,<4.0",
15
- "ssot-contracts==0.2.17.dev1",
16
- "ssot-views==0.2.17.dev1",
15
+ "ssot-contracts==0.2.18.dev9",
16
+ "ssot-pack-contracts>=0.2.17,<0.3.0",
17
+ "ssot-views==0.2.18.dev9",
17
18
  "tomli>=2.0.1; python_version < '3.11'",
18
19
  ]
19
20
  keywords = ["ssot", "core", "registry", "validation", "release-management", "governance", "compliance"]
@@ -31,6 +32,7 @@ classifiers = [
31
32
  "Programming Language :: Python :: 3.11",
32
33
  "Programming Language :: Python :: 3.12",
33
34
  "Programming Language :: Python :: 3.13",
35
+ "Programming Language :: Python :: 3.14",
34
36
  "Topic :: Database",
35
37
  "Topic :: File Formats :: JSON",
36
38
  "Topic :: File Formats :: JSON :: JSON Schema",
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ssot-core
3
- Version: 0.2.17.dev1
3
+ Version: 0.2.18.dev9
4
4
  Summary: Core Python runtime, registry model, validation, and release workflow APIs for SSOT.
5
5
  Author-email: Jacob Stewart <jacob@swarmauri.com>
6
6
  License-Expression: Apache-2.0
@@ -21,6 +21,7 @@ Classifier: Programming Language :: Python :: 3.10
21
21
  Classifier: Programming Language :: Python :: 3.11
22
22
  Classifier: Programming Language :: Python :: 3.12
23
23
  Classifier: Programming Language :: Python :: 3.13
24
+ Classifier: Programming Language :: Python :: 3.14
24
25
  Classifier: Topic :: Database
25
26
  Classifier: Topic :: File Formats :: JSON
26
27
  Classifier: Topic :: File Formats :: JSON :: JSON Schema
@@ -32,11 +33,12 @@ Classifier: Topic :: Software Development :: Quality Assurance
32
33
  Classifier: Topic :: Software Development :: Testing
33
34
  Classifier: Topic :: System :: Archiving
34
35
  Classifier: Topic :: Utilities
35
- Requires-Python: <3.14,>=3.10
36
+ Requires-Python: <3.15,>=3.10
36
37
  Description-Content-Type: text/markdown
37
38
  Requires-Dist: orjson<4.0,>=3.10
38
- Requires-Dist: ssot-contracts==0.2.17.dev1
39
- Requires-Dist: ssot-views==0.2.17.dev1
39
+ Requires-Dist: ssot-contracts==0.2.18.dev9
40
+ Requires-Dist: ssot-pack-contracts<0.3.0,>=0.2.17
41
+ Requires-Dist: ssot-views==0.2.18.dev9
40
42
  Requires-Dist: tomli>=2.0.1; python_version < "3.11"
41
43
 
42
44
  <div align="center">
@@ -49,6 +51,10 @@ Requires-Dist: tomli>=2.0.1; python_version < "3.11"
49
51
  <a href="https://pypi.org/project/ssot-core/"><img src="https://img.shields.io/pypi/pyversions/ssot-core?label=Python" alt="Supported Python versions" /></a>
50
52
  <a href="https://pepy.tech/project/ssot-core"><img src="https://static.pepy.tech/badge/ssot-core" alt="Downloads" /></a>
51
53
  <a href="https://hits.sh/github.com/groupsum/ssot-registry/"><img src="https://hits.sh/github.com/groupsum/ssot-registry.svg?style=flat-square" alt="Hits" /></a>
54
+ <!-- ssot-schema-badges:start -->
55
+ <img src="https://img.shields.io/badge/schema_version-0.5.0-blue" alt="schema_version 0.5.0" />
56
+ <img src="https://img.shields.io/badge/migration%20coverage-12%2F12-brightgreen" alt="Migration coverage 12/12" />
57
+ <!-- ssot-schema-badges:end -->
52
58
  </div>
53
59
 
54
60
  `ssot-core` is the core Python runtime package for SSOT.
@@ -11,6 +11,7 @@ src/ssot_registry/version.py
11
11
  src/ssot_registry/api/__init__.py
12
12
  src/ssot_registry/api/boundary.py
13
13
  src/ssot_registry/api/claims.py
14
+ src/ssot_registry/api/config.py
14
15
  src/ssot_registry/api/documents.py
15
16
  src/ssot_registry/api/entity_ops.py
16
17
  src/ssot_registry/api/evidence.py
@@ -18,6 +19,9 @@ src/ssot_registry/api/graph.py
18
19
  src/ssot_registry/api/init.py
19
20
  src/ssot_registry/api/lifecycle.py
20
21
  src/ssot_registry/api/load.py
22
+ src/ssot_registry/api/local_assurance.py
23
+ src/ssot_registry/api/origin.py
24
+ src/ssot_registry/api/packs.py
21
25
  src/ssot_registry/api/plan.py
22
26
  src/ssot_registry/api/profile_eval.py
23
27
  src/ssot_registry/api/profile_resolution.py
@@ -53,6 +57,7 @@ src/ssot_registry/graph/export_json.py
53
57
  src/ssot_registry/guards/__init__.py
54
58
  src/ssot_registry/guards/certification.py
55
59
  src/ssot_registry/guards/claim_closure.py
60
+ src/ssot_registry/guards/claim_tier_gates.py
56
61
  src/ssot_registry/guards/document_lifecycle.py
57
62
  src/ssot_registry/guards/document_supersession.py
58
63
  src/ssot_registry/guards/feature_claims.py
@@ -100,11 +105,13 @@ src/ssot_registry/util/time.py
100
105
  src/ssot_registry/validators/__init__.py
101
106
  src/ssot_registry/validators/bidirectional.py
102
107
  src/ssot_registry/validators/bounds.py
108
+ src/ssot_registry/validators/claim_lineage.py
103
109
  src/ssot_registry/validators/coverage.py
104
110
  src/ssot_registry/validators/documents.py
105
111
  src/ssot_registry/validators/filesystem.py
106
112
  src/ssot_registry/validators/identity.py
107
113
  src/ssot_registry/validators/lifecycle.py
114
+ src/ssot_registry/validators/origin.py
108
115
  src/ssot_registry/validators/promotion.py
109
116
  src/ssot_registry/validators/references.py
110
117
  src/ssot_registry/validators/reservations.py
@@ -0,0 +1,7 @@
1
+ orjson<4.0,>=3.10
2
+ ssot-contracts==0.2.18.dev9
3
+ ssot-pack-contracts<0.3.0,>=0.2.17
4
+ ssot-views==0.2.18.dev9
5
+
6
+ [:python_version < "3.11"]
7
+ tomli>=2.0.1
@@ -1,5 +1,6 @@
1
1
  from .boundary import freeze_boundary
2
2
  from .claims import evaluate_claims
3
+ from .config import ensure_repo_config, load_repo_config, run_repo_automation, validate_repo_config
3
4
  from .documents import (
4
5
  create_document,
5
6
  create_document_reservation,
@@ -9,6 +10,7 @@ from .documents import (
9
10
  list_document_reservations,
10
11
  list_documents,
11
12
  remove_spec_adr_links,
13
+ repair_document_hashes,
12
14
  set_document_status,
13
15
  sync_all_documents,
14
16
  sync_documents,
@@ -42,9 +44,18 @@ from .profile_eval import evaluate_feature_passing, evaluate_profile, evaluate_p
42
44
  from .evidence import verify_evidence_rows
43
45
  from .graph import export_graph
44
46
  from .init import initialize_repo
47
+ from .local_assurance import (
48
+ build_artifact_manifest,
49
+ build_local_evidence_bundle,
50
+ build_source_snapshot,
51
+ deterministic_root_hash,
52
+ verify_local_release,
53
+ )
45
54
  from .lifecycle import set_feature_lifecycle
46
55
  from .load import load_registry
47
56
  from .plan import plan_features, plan_issues
57
+ from .packs import inspect_pack, preflight_pack, sync_pack
58
+ from .origin import sync_origin_assurance_rows
48
59
  from .registry import export_registry
49
60
  from .release import certify_release, promote_release, publish_release, revoke_release
50
61
  from .save import save_registry
@@ -58,12 +69,17 @@ __all__ = [
58
69
  "load_registry",
59
70
  "save_registry",
60
71
  "validate_registry",
72
+ "ensure_repo_config",
73
+ "load_repo_config",
74
+ "validate_repo_config",
75
+ "run_repo_automation",
61
76
  "create_document",
62
77
  "get_document",
63
78
  "list_documents",
64
79
  "update_document",
65
80
  "add_spec_adr_links",
66
81
  "remove_spec_adr_links",
82
+ "repair_document_hashes",
67
83
  "set_document_status",
68
84
  "supersede_documents",
69
85
  "delete_document",
@@ -94,7 +110,16 @@ __all__ = [
94
110
  "remove_release_evidence",
95
111
  "plan_features",
96
112
  "plan_issues",
113
+ "inspect_pack",
114
+ "preflight_pack",
115
+ "sync_pack",
116
+ "sync_origin_assurance_rows",
97
117
  "set_feature_lifecycle",
118
+ "build_artifact_manifest",
119
+ "build_local_evidence_bundle",
120
+ "build_source_snapshot",
121
+ "deterministic_root_hash",
122
+ "verify_local_release",
98
123
  "evaluate_claims",
99
124
  "evaluate_feature_passing",
100
125
  "evaluate_profile",
@@ -3,12 +3,13 @@ from __future__ import annotations
3
3
  from pathlib import Path
4
4
 
5
5
  from ssot_registry.guards.claim_closure import evaluate_claim_guard
6
+ from ssot_registry.guards.claim_tier_gates import evaluate_claim_tier_gate
6
7
  from ssot_registry.validators.identity import build_index
7
8
  from .load import load_registry
8
9
 
9
10
 
10
- def evaluate_claims(path: str | Path, claim_id: str | None = None) -> dict[str, object]:
11
- registry_path, _repo_root, registry = load_registry(path)
11
+ def evaluate_claims(path: str | Path, claim_id: str | None = None, *, include_tier_gate: bool = False) -> dict[str, object]:
12
+ registry_path, repo_root, registry = load_registry(path)
12
13
  failures: list[str] = []
13
14
  index = build_index(registry, failures)
14
15
 
@@ -25,8 +26,26 @@ def evaluate_claims(path: str | Path, claim_id: str | None = None) -> dict[str,
25
26
  if claim_id is not None
26
27
  else [index["claims"][entity_id] for entity_id in sorted(index["claims"])]
27
28
  )
28
- reports = [evaluate_claim_guard(claim, index, registry.get("guard_policies", {})) for claim in selected]
29
+ reports = []
30
+ for claim in selected:
31
+ report = evaluate_claim_guard(claim, index, registry.get("guard_policies", {}))
32
+ if include_tier_gate:
33
+ report["tier_gate"] = evaluate_claim_tier_gate(
34
+ registry,
35
+ claim,
36
+ index,
37
+ str(claim.get("tier", "T0")),
38
+ repo_root=repo_root,
39
+ policy=registry.get("guard_policies", {}).get("claim_tier_gates", {}),
40
+ )
41
+ reports.append(report)
29
42
  all_failures = failures + [failure for report in reports for failure in report["failures"]]
43
+ if include_tier_gate:
44
+ all_failures.extend(
45
+ failure
46
+ for report in reports
47
+ for failure in report.get("tier_gate", {}).get("failures", [])
48
+ )
30
49
  return {
31
50
  "passed": not all_failures,
32
51
  "registry_path": registry_path.as_posix(),
@@ -0,0 +1,283 @@
1
+ from __future__ import annotations
2
+
3
+ from copy import deepcopy
4
+ from pathlib import Path
5
+ from typing import Any
6
+
7
+ from ssot_registry.util.errors import ValidationError
8
+
9
+ from .graph import export_graph
10
+ from .validate import validate_registry
11
+
12
+ try:
13
+ import tomllib
14
+ except ModuleNotFoundError: # pragma: no cover - Python < 3.11
15
+ import tomli as tomllib
16
+
17
+
18
+ CONFIG_RELATIVE_PATH = ".ssot/ssot.toml"
19
+ _AUTOMATION_MODE_CHOICES = {"manual", "automatic"}
20
+ _GRAPH_FORMAT_CHOICES = {"json", "dot", "png", "svg"}
21
+
22
+ _DEFAULT_CONFIG: dict[str, Any] = {
23
+ "policy": {
24
+ "interactive": False,
25
+ "fail_closed": True,
26
+ },
27
+ "sync": {
28
+ "docs": "manual",
29
+ "templates": "manual",
30
+ "upstream_packages": "manual",
31
+ },
32
+ "validate": {
33
+ "after_registry_change": "automatic",
34
+ },
35
+ "generation": {
36
+ "mode": "manual",
37
+ "formats": ["json"],
38
+ "targets": {
39
+ "graphs": False,
40
+ },
41
+ "graphs": {
42
+ "mode": "manual",
43
+ "formats": ["json"],
44
+ "output_dir": ".ssot/graphs",
45
+ "basename": "registry.graph",
46
+ },
47
+ },
48
+ }
49
+
50
+ _DEFAULT_TEMPLATE = """[policy]
51
+ interactive = false
52
+ fail_closed = true
53
+
54
+ [sync]
55
+ docs = "manual"
56
+ templates = "manual"
57
+ upstream_packages = "manual"
58
+
59
+ [validate]
60
+ after_registry_change = "automatic"
61
+
62
+ [generation]
63
+ mode = "manual"
64
+ formats = ["json"]
65
+
66
+ [generation.targets]
67
+ graphs = false
68
+
69
+ [generation.graphs]
70
+ mode = "manual"
71
+ formats = ["json"]
72
+ output_dir = ".ssot/graphs"
73
+ basename = "registry.graph"
74
+ """
75
+
76
+ _AUTOMATION_DEPTH = 0
77
+
78
+
79
+ def _repo_root_from_path(path: str | Path) -> Path:
80
+ candidate = Path(path).expanduser()
81
+ if candidate.is_file():
82
+ if candidate.name == "registry.json" and candidate.parent.name == ".ssot":
83
+ return candidate.parent.parent
84
+ if candidate.parent.name == ".ssot":
85
+ return candidate.parent.parent
86
+ return candidate.parent
87
+ if candidate.name == ".ssot":
88
+ return candidate.parent
89
+ return candidate
90
+
91
+
92
+ def _config_path(repo_root: Path) -> Path:
93
+ return repo_root / CONFIG_RELATIVE_PATH
94
+
95
+
96
+ def _deep_merge(base: dict[str, Any], override: dict[str, Any]) -> dict[str, Any]:
97
+ merged = deepcopy(base)
98
+ for key, value in override.items():
99
+ current = merged.get(key)
100
+ if isinstance(current, dict) and isinstance(value, dict):
101
+ merged[key] = _deep_merge(current, value)
102
+ else:
103
+ merged[key] = deepcopy(value)
104
+ return merged
105
+
106
+
107
+ def _expect_table(config: dict[str, Any], key: str) -> dict[str, Any]:
108
+ value = config.get(key)
109
+ if not isinstance(value, dict):
110
+ raise ValidationError(f"{key} must be a TOML table")
111
+ return value
112
+
113
+
114
+ def _expect_bool(table: dict[str, Any], key: str, *, prefix: str) -> None:
115
+ value = table.get(key)
116
+ if not isinstance(value, bool):
117
+ raise ValidationError(f"{prefix}.{key} must be a boolean")
118
+
119
+
120
+ def _expect_choice(table: dict[str, Any], key: str, choices: set[str], *, prefix: str) -> None:
121
+ value = table.get(key)
122
+ if not isinstance(value, str) or value not in choices:
123
+ allowed = ", ".join(sorted(choices))
124
+ raise ValidationError(f"{prefix}.{key} must be one of: {allowed}")
125
+
126
+
127
+ def _expect_string(table: dict[str, Any], key: str, *, prefix: str) -> None:
128
+ value = table.get(key)
129
+ if not isinstance(value, str) or not value.strip():
130
+ raise ValidationError(f"{prefix}.{key} must be a non-empty string")
131
+
132
+
133
+ def _expect_scalar_string_list(table: dict[str, Any], key: str, choices: set[str] | None = None, *, prefix: str) -> None:
134
+ value = table.get(key)
135
+ if not isinstance(value, list) or any(not isinstance(item, str) for item in value):
136
+ raise ValidationError(f"{prefix}.{key} must be a list of strings")
137
+ if choices is not None:
138
+ invalid = [item for item in value if item not in choices]
139
+ if invalid:
140
+ allowed = ", ".join(sorted(choices))
141
+ raise ValidationError(f"{prefix}.{key} contains unsupported values {invalid}; allowed: {allowed}")
142
+
143
+
144
+ def validate_repo_config_payload(config: dict[str, Any]) -> dict[str, Any]:
145
+ normalized = _deep_merge(_DEFAULT_CONFIG, config)
146
+
147
+ policy = _expect_table(normalized, "policy")
148
+ _expect_bool(policy, "interactive", prefix="policy")
149
+ _expect_bool(policy, "fail_closed", prefix="policy")
150
+
151
+ sync = _expect_table(normalized, "sync")
152
+ for field_name in ("docs", "templates", "upstream_packages"):
153
+ _expect_choice(sync, field_name, _AUTOMATION_MODE_CHOICES, prefix="sync")
154
+
155
+ validate_cfg = _expect_table(normalized, "validate")
156
+ _expect_choice(validate_cfg, "after_registry_change", _AUTOMATION_MODE_CHOICES, prefix="validate")
157
+
158
+ generation = _expect_table(normalized, "generation")
159
+ _expect_choice(generation, "mode", _AUTOMATION_MODE_CHOICES, prefix="generation")
160
+ _expect_scalar_string_list(generation, "formats", choices={"json", "yaml", "toml", "md", "dot", "png", "svg"}, prefix="generation")
161
+
162
+ targets = _expect_table(generation, "targets")
163
+ _expect_bool(targets, "graphs", prefix="generation.targets")
164
+
165
+ graphs = _expect_table(generation, "graphs")
166
+ _expect_choice(graphs, "mode", _AUTOMATION_MODE_CHOICES, prefix="generation.graphs")
167
+ _expect_scalar_string_list(graphs, "formats", choices=_GRAPH_FORMAT_CHOICES, prefix="generation.graphs")
168
+ _expect_string(graphs, "output_dir", prefix="generation.graphs")
169
+ _expect_string(graphs, "basename", prefix="generation.graphs")
170
+
171
+ return normalized
172
+
173
+
174
+ def ensure_repo_config(path: str | Path, *, overwrite: bool = False) -> dict[str, Any]:
175
+ repo_root = _repo_root_from_path(path)
176
+ repo_root.mkdir(parents=True, exist_ok=True)
177
+ config_path = _config_path(repo_root)
178
+ config_path.parent.mkdir(parents=True, exist_ok=True)
179
+ existed = config_path.exists()
180
+
181
+ if existed and not overwrite:
182
+ payload = load_repo_config(path)
183
+ return {
184
+ "passed": True,
185
+ "config_path": payload["config_path"],
186
+ "created": False,
187
+ "overwritten": False,
188
+ "config": payload["config"],
189
+ }
190
+
191
+ config_path.write_text(_DEFAULT_TEMPLATE, encoding="utf-8", newline="\n")
192
+ payload = load_repo_config(path)
193
+ return {
194
+ "passed": True,
195
+ "config_path": payload["config_path"],
196
+ "created": not existed,
197
+ "overwritten": existed and overwrite,
198
+ "config": payload["config"],
199
+ }
200
+
201
+
202
+ def load_repo_config(path: str | Path) -> dict[str, Any]:
203
+ repo_root = _repo_root_from_path(path)
204
+ config_path = _config_path(repo_root)
205
+ if not config_path.exists():
206
+ raise FileNotFoundError(f"Repo-local SSOT config not found: {config_path.as_posix()}")
207
+ raw = tomllib.loads(config_path.read_text(encoding="utf-8"))
208
+ if not isinstance(raw, dict):
209
+ raise ValidationError("Repo-local SSOT config must decode to a TOML table")
210
+ normalized = validate_repo_config_payload(raw)
211
+ return {
212
+ "passed": True,
213
+ "repo_root": repo_root.as_posix(),
214
+ "config_path": config_path.as_posix(),
215
+ "config": normalized,
216
+ }
217
+
218
+
219
+ def validate_repo_config(path: str | Path) -> dict[str, Any]:
220
+ payload = load_repo_config(path)
221
+ return {
222
+ "passed": True,
223
+ "repo_root": payload["repo_root"],
224
+ "config_path": payload["config_path"],
225
+ "config": payload["config"],
226
+ }
227
+
228
+
229
+ def run_repo_automation(path: str | Path) -> dict[str, Any]:
230
+ global _AUTOMATION_DEPTH
231
+
232
+ try:
233
+ payload = load_repo_config(path)
234
+ except FileNotFoundError as exc:
235
+ return {
236
+ "passed": True,
237
+ "config_path": str(exc).removeprefix("Repo-local SSOT config not found: "),
238
+ "skipped": True,
239
+ "sync": None,
240
+ "validation": None,
241
+ "generation": {
242
+ "graphs": [],
243
+ },
244
+ }
245
+ config = payload["config"]
246
+ results: dict[str, Any] = {
247
+ "passed": True,
248
+ "config_path": payload["config_path"],
249
+ "skipped": False,
250
+ "sync": None,
251
+ "validation": None,
252
+ "generation": {
253
+ "graphs": [],
254
+ },
255
+ }
256
+ if _AUTOMATION_DEPTH > 0:
257
+ results["skipped"] = True
258
+ return results
259
+
260
+ _AUTOMATION_DEPTH += 1
261
+ try:
262
+ if config["sync"]["docs"] == "automatic":
263
+ from .documents import sync_all_documents
264
+
265
+ results["sync"] = sync_all_documents(path)
266
+
267
+ if config["validate"]["after_registry_change"] == "automatic":
268
+ validation = validate_registry(path)
269
+ if not validation["passed"] and config["policy"]["fail_closed"]:
270
+ raise ValidationError("Repo-local automation validation failed after registry change")
271
+ results["validation"] = validation
272
+
273
+ graph_cfg = config["generation"]["graphs"]
274
+ if config["generation"]["targets"]["graphs"] and graph_cfg["mode"] == "automatic":
275
+ repo_root = Path(payload["repo_root"])
276
+ for output_format in graph_cfg["formats"]:
277
+ output_path = repo_root / graph_cfg["output_dir"] / f"{graph_cfg['basename']}.{output_format}"
278
+ graph_result = export_graph(path=path, output_format=output_format, output=output_path.as_posix())
279
+ results["generation"]["graphs"].append(graph_result["output_path"])
280
+ finally:
281
+ _AUTOMATION_DEPTH -= 1
282
+
283
+ return results