assertions-mate 0.2.0__tar.gz → 0.5.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 (143) hide show
  1. assertions_mate-0.5.0/.env +1 -0
  2. {assertions_mate-0.2.0 → assertions_mate-0.5.0}/.gitignore +3 -1
  3. assertions_mate-0.5.0/CHANGELOG.md +73 -0
  4. {assertions_mate-0.2.0 → assertions_mate-0.5.0}/PKG-INFO +15 -11
  5. {assertions_mate-0.2.0 → assertions_mate-0.5.0}/README.md +6 -0
  6. assertions_mate-0.5.0/Taskfile.yaml +46 -0
  7. assertions_mate-0.5.0/docs/explanation/architecture.md +66 -0
  8. assertions_mate-0.5.0/docs/explanation/compatibility-and-limitations.md +40 -0
  9. assertions_mate-0.5.0/docs/explanation/testing-and-reliability.md +32 -0
  10. assertions_mate-0.5.0/docs/how-to/add-cql2-polygon-area-function.md +57 -0
  11. assertions_mate-0.5.0/docs/how-to/author-cql2-json-encoding.md +46 -0
  12. assertions_mate-0.5.0/docs/how-to/combine-multiple-hints.md +57 -0
  13. assertions_mate-0.5.0/docs/how-to/create-reusable-rego-snippets.md +52 -0
  14. assertions_mate-0.5.0/docs/how-to/test-hints-with-pytest.md +27 -0
  15. assertions_mate-0.5.0/docs/how-to/troubleshoot-cwl-loader-errors.md +19 -0
  16. assertions_mate-0.5.0/docs/how-to/troubleshoot-rego-invalid-literal.md +32 -0
  17. assertions_mate-0.5.0/docs/how-to/use-packed-vs-single-cwl.md +28 -0
  18. assertions_mate-0.5.0/docs/how-to/validate-array-cardinality-jsonschema.md +48 -0
  19. assertions_mate-0.5.0/docs/how-to/validate-bbox-overlap-cql2.md +53 -0
  20. assertions_mate-0.5.0/docs/how-to/validate-conditional-required-rego.md +46 -0
  21. assertions_mate-0.5.0/docs/how-to/validate-cross-field-dependency-rego.md +46 -0
  22. assertions_mate-0.5.0/docs/how-to/validate-date-range-inputs.md +85 -0
  23. assertions_mate-0.5.0/docs/how-to/validate-datetime-input.md +83 -0
  24. assertions_mate-0.5.0/docs/how-to/validate-datetime-window-rego.md +64 -0
  25. assertions_mate-0.5.0/docs/how-to/validate-disjoint-geometries-cql2.md +38 -0
  26. assertions_mate-0.5.0/docs/how-to/validate-enum-jsonschema.md +45 -0
  27. assertions_mate-0.5.0/docs/how-to/validate-numeric-range-rego.md +48 -0
  28. assertions_mate-0.5.0/docs/how-to/validate-optional-input-rego.md +51 -0
  29. assertions_mate-0.5.0/docs/how-to/validate-point-in-polygon-cql2.md +43 -0
  30. assertions_mate-0.5.0/docs/how-to/validate-polygon-area-cql2.md +42 -0
  31. assertions_mate-0.5.0/docs/how-to/validate-polygon-intersects-aoi-cql2.md +38 -0
  32. assertions_mate-0.5.0/docs/how-to/validate-polygon-parameter.md +82 -0
  33. assertions_mate-0.5.0/docs/how-to/validate-required-property-rego.md +41 -0
  34. assertions_mate-0.5.0/docs/how-to/validate-uri-host-rego.md +57 -0
  35. assertions_mate-0.5.0/docs/how-to/validate-uri-input.md +78 -0
  36. assertions_mate-0.5.0/docs/index.md +44 -0
  37. {assertions_mate-0.2.0 → assertions_mate-0.5.0}/docs/jsonschema.ipynb +10 -2
  38. assertions_mate-0.5.0/docs/pygeofilter.ipynb +3070 -0
  39. assertions_mate-0.5.0/docs/reference/cli.md +41 -0
  40. assertions_mate-0.5.0/docs/reference/errors.md +50 -0
  41. assertions_mate-0.5.0/docs/reference/hints.md +60 -0
  42. assertions_mate-0.5.0/docs/reference/hints_schema.html +226 -0
  43. assertions_mate-0.5.0/docs/reference/runtime-compatibility.md +53 -0
  44. {assertions_mate-0.2.0 → assertions_mate-0.5.0}/docs/regopy.ipynb +39 -22
  45. assertions_mate-0.5.0/docs/tutorials/first-validated-workflow.md +93 -0
  46. assertions_mate-0.5.0/examples/array-cardinality-validation/inputs-invalid.yaml +1 -0
  47. assertions_mate-0.5.0/examples/array-cardinality-validation/inputs-valid.yaml +1 -0
  48. assertions_mate-0.5.0/examples/array-cardinality-validation/workflow.cwl +20 -0
  49. assertions_mate-0.5.0/examples/bbox-overlap-validation/inputs-invalid.yaml +2 -0
  50. assertions_mate-0.5.0/examples/bbox-overlap-validation/inputs-valid.yaml +2 -0
  51. assertions_mate-0.5.0/examples/bbox-overlap-validation/workflow.cwl +33 -0
  52. assertions_mate-0.5.0/examples/conditional-required-validation/inputs-invalid.yaml +2 -0
  53. assertions_mate-0.5.0/examples/conditional-required-validation/inputs-valid.yaml +9 -0
  54. assertions_mate-0.5.0/examples/conditional-required-validation/workflow.cwl +24 -0
  55. assertions_mate-0.5.0/examples/cql2-json-validation/inputs-invalid.yaml +1 -0
  56. assertions_mate-0.5.0/examples/cql2-json-validation/inputs-valid.yaml +1 -0
  57. assertions_mate-0.5.0/examples/cql2-json-validation/workflow.cwl +18 -0
  58. assertions_mate-0.5.0/examples/cross-field-dependency-validation/inputs-invalid.yaml +2 -0
  59. assertions_mate-0.5.0/examples/cross-field-dependency-validation/inputs-valid.yaml +2 -0
  60. assertions_mate-0.5.0/examples/cross-field-dependency-validation/workflow.cwl +24 -0
  61. assertions_mate-0.5.0/examples/date-range-validation/README.md +30 -0
  62. assertions_mate-0.5.0/examples/date-range-validation/inputs-invalid.yaml +4 -0
  63. assertions_mate-0.5.0/examples/date-range-validation/inputs-null.yaml +4 -0
  64. assertions_mate-0.5.0/examples/date-range-validation/inputs-valid.yaml +4 -0
  65. assertions_mate-0.5.0/examples/date-range-validation/workflow.cwl +79 -0
  66. assertions_mate-0.5.0/examples/datetime-validation/README.md +30 -0
  67. assertions_mate-0.5.0/examples/datetime-validation/inputs-invalid.yaml +2 -0
  68. assertions_mate-0.5.0/examples/datetime-validation/inputs-null.yaml +2 -0
  69. assertions_mate-0.5.0/examples/datetime-validation/inputs-valid.yaml +2 -0
  70. assertions_mate-0.5.0/examples/datetime-validation/workflow.cwl +46 -0
  71. assertions_mate-0.5.0/examples/datetime-window-validation/inputs-invalid.yaml +2 -0
  72. assertions_mate-0.5.0/examples/datetime-window-validation/inputs-valid.yaml +2 -0
  73. assertions_mate-0.5.0/examples/datetime-window-validation/workflow.cwl +35 -0
  74. assertions_mate-0.5.0/examples/disjoint-geometries-validation/inputs-invalid.yaml +16 -0
  75. assertions_mate-0.5.0/examples/disjoint-geometries-validation/inputs-valid.yaml +16 -0
  76. assertions_mate-0.5.0/examples/disjoint-geometries-validation/workflow.cwl +16 -0
  77. assertions_mate-0.5.0/examples/enum-validation/inputs-invalid.yaml +1 -0
  78. assertions_mate-0.5.0/examples/enum-validation/inputs-valid.yaml +1 -0
  79. assertions_mate-0.5.0/examples/enum-validation/workflow.cwl +17 -0
  80. assertions_mate-0.5.0/examples/multi-hint-validation/inputs-invalid.yaml +17 -0
  81. assertions_mate-0.5.0/examples/multi-hint-validation/inputs-valid.yaml +17 -0
  82. assertions_mate-0.5.0/examples/multi-hint-validation/workflow.cwl +36 -0
  83. assertions_mate-0.5.0/examples/numeric-range-validation/inputs-invalid.yaml +1 -0
  84. assertions_mate-0.5.0/examples/numeric-range-validation/inputs-valid.yaml +1 -0
  85. assertions_mate-0.5.0/examples/numeric-range-validation/workflow.cwl +26 -0
  86. assertions_mate-0.5.0/examples/optional-input-validation/inputs-invalid.yaml +1 -0
  87. assertions_mate-0.5.0/examples/optional-input-validation/inputs-valid.yaml +1 -0
  88. assertions_mate-0.5.0/examples/optional-input-validation/workflow.cwl +23 -0
  89. assertions_mate-0.5.0/examples/point-in-polygon-validation/README.md +23 -0
  90. assertions_mate-0.5.0/examples/point-in-polygon-validation/inputs-invalid.yaml +11 -0
  91. assertions_mate-0.5.0/examples/point-in-polygon-validation/inputs-valid.yaml +11 -0
  92. assertions_mate-0.5.0/examples/point-in-polygon-validation/workflow.cwl +23 -0
  93. assertions_mate-0.5.0/examples/polygon-intersects-validation/inputs-invalid.yaml +16 -0
  94. assertions_mate-0.5.0/examples/polygon-intersects-validation/inputs-valid.yaml +16 -0
  95. assertions_mate-0.5.0/examples/polygon-intersects-validation/workflow.cwl +16 -0
  96. assertions_mate-0.5.0/examples/polygon-validation/README.md +23 -0
  97. assertions_mate-0.5.0/examples/polygon-validation/inputs-invalid.yaml +4 -0
  98. assertions_mate-0.5.0/examples/polygon-validation/inputs-null.yaml +1 -0
  99. assertions_mate-0.5.0/examples/polygon-validation/inputs-valid.yaml +9 -0
  100. assertions_mate-0.5.0/examples/polygon-validation/workflow.cwl +27 -0
  101. assertions_mate-0.5.0/examples/pytest-validation/test_validators_example.py +20 -0
  102. assertions_mate-0.5.0/examples/required-property-validation/inputs-invalid.yaml +9 -0
  103. assertions_mate-0.5.0/examples/required-property-validation/inputs-valid.yaml +10 -0
  104. assertions_mate-0.5.0/examples/required-property-validation/workflow.cwl +19 -0
  105. assertions_mate-0.5.0/examples/reusable-rego-snippets/inputs-invalid.yaml +2 -0
  106. assertions_mate-0.5.0/examples/reusable-rego-snippets/inputs-valid.yaml +2 -0
  107. assertions_mate-0.5.0/examples/reusable-rego-snippets/workflow.cwl +32 -0
  108. assertions_mate-0.5.0/examples/uri-host-validation/inputs-invalid.yaml +1 -0
  109. assertions_mate-0.5.0/examples/uri-host-validation/inputs-valid.yaml +1 -0
  110. assertions_mate-0.5.0/examples/uri-host-validation/workflow.cwl +26 -0
  111. assertions_mate-0.5.0/examples/uri-validation/README.md +30 -0
  112. assertions_mate-0.5.0/examples/uri-validation/inputs-invalid.yaml +2 -0
  113. assertions_mate-0.5.0/examples/uri-validation/inputs-null.yaml +2 -0
  114. assertions_mate-0.5.0/examples/uri-validation/inputs-valid.yaml +2 -0
  115. assertions_mate-0.5.0/examples/uri-validation/workflow.cwl +46 -0
  116. assertions_mate-0.5.0/mkdocs.yaml +137 -0
  117. {assertions_mate-0.2.0 → assertions_mate-0.5.0}/pyproject.toml +17 -19
  118. {assertions_mate-0.2.0 → assertions_mate-0.5.0}/schemas/hints.yaml +16 -6
  119. {assertions_mate-0.2.0 → assertions_mate-0.5.0}/src/assertions_mate/__about__.py +1 -1
  120. {assertions_mate-0.2.0 → assertions_mate-0.5.0}/src/assertions_mate/__init__.py +4 -2
  121. {assertions_mate-0.2.0 → assertions_mate-0.5.0}/src/assertions_mate/cql2_validator.py +24 -19
  122. {assertions_mate-0.2.0 → assertions_mate-0.5.0}/src/assertions_mate/rego_validator.py +1 -1
  123. assertions_mate-0.5.0/tests/test_cql2_validator.py +86 -0
  124. assertions_mate-0.5.0/tests/test_howto_hints.py +83 -0
  125. assertions_mate-0.2.0/Taskfile.yaml +0 -32
  126. assertions_mate-0.2.0/docs/index.md +0 -9
  127. assertions_mate-0.2.0/docs/pygeofilter.ipynb +0 -191
  128. assertions_mate-0.2.0/mkdocs.yaml +0 -102
  129. assertions_mate-0.2.0/tests/test_cql2_validator.py +0 -51
  130. {assertions_mate-0.2.0 → assertions_mate-0.5.0}/.github/workflows/docs.yaml +0 -0
  131. {assertions_mate-0.2.0 → assertions_mate-0.5.0}/.github/workflows/package.yaml +0 -0
  132. {assertions_mate-0.2.0 → assertions_mate-0.5.0}/LICENSE +0 -0
  133. {assertions_mate-0.2.0 → assertions_mate-0.5.0}/NOTICE +0 -0
  134. {assertions_mate-0.2.0 → assertions_mate-0.5.0}/docs/diagrams/src/class.puml +0 -0
  135. {assertions_mate-0.2.0 → assertions_mate-0.5.0}/docs/diagrams/src/flow.puml +0 -0
  136. {assertions_mate-0.2.0 → assertions_mate-0.5.0}/docs/diagrams/src/overall.puml +0 -0
  137. {assertions_mate-0.2.0 → assertions_mate-0.5.0}/docs/diagrams/src/sequence.puml +0 -0
  138. {assertions_mate-0.2.0 → assertions_mate-0.5.0}/src/assertions_mate/cli.py +0 -0
  139. {assertions_mate-0.2.0 → assertions_mate-0.5.0}/src/assertions_mate/error_models.py +0 -0
  140. {assertions_mate-0.2.0 → assertions_mate-0.5.0}/src/assertions_mate/jsonschema_validator.py +0 -0
  141. {assertions_mate-0.2.0 → assertions_mate-0.5.0}/tests/artifacts/request_body.yaml +0 -0
  142. {assertions_mate-0.2.0 → assertions_mate-0.5.0}/tests/test_hints.py +0 -0
  143. {assertions_mate-0.2.0 → assertions_mate-0.5.0}/tests/test_jsonschema_validator.py +0 -0
@@ -0,0 +1 @@
1
+ TASK_X_REMOTE_TASKFILES=1
@@ -6,4 +6,6 @@ docs/diagrams/out
6
6
  openapi_bundled.yaml
7
7
  *.pyc
8
8
  schema.yaml
9
- src/assertions_mate/__pycache__
9
+ src/assertions_mate/__pycache__
10
+ .task
11
+ .vscode
@@ -0,0 +1,73 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [Unreleased]
9
+
10
+ ### Added
11
+
12
+ ### Changed
13
+
14
+ ### Deprecated
15
+
16
+ ### Removed
17
+
18
+ ### Fixed
19
+
20
+ ### Security
21
+
22
+ ## [0.4.0] - 2026-05-29
23
+
24
+ ### Added
25
+
26
+ - Expanded the documentation site with Diataxis-oriented tutorials, how-to guides, reference pages, and explanation pages.
27
+ - Added runnable CWL examples for URI, datetime, date range, polygon, bbox overlap, CQL2 JSON, enum, array cardinality, multi-hint, Rego, and pytest-based validation workflows.
28
+ - Added generated schema reference documentation for assertion hints.
29
+ - Added support for `Cql2FilterHint.custom_functions`, allowing CWL hints to provide Python functions used by CQL2 validation.
30
+ - Added tests that exercise how-to hint extraction and CQL2 custom function execution.
31
+
32
+ ### Changed
33
+
34
+ - Changed assertion schema records to extend `cwl:ProcessRequirement` instead of `cwl:ProcessHint`.
35
+ - Updated the CQL2 hint schema with field documentation and links to CQL2 and Rego references.
36
+ - Moved the default Taskfile workflow to remote shared quality tasks and added documentation/schema-generation tasks.
37
+ - Updated package metadata through `0.4.0`; the repository currently has no Git tags after `v0.2.0`.
38
+
39
+ ### Fixed
40
+
41
+ - Normalized CWL/YAML scalar values before parsing CQL2 JSON filters.
42
+ - Updated Rego validation to use the default regopy interpreter setup, avoiding runtime issues with supported policy syntax.
43
+ - Fixed URI and datetime examples to validate typed input payloads through their `value` fields.
44
+ - Fixed and expanded CQL2 bbox validation examples to use custom functions declared in the CWL hint.
45
+ - Fixed MkDocs configuration and documentation navigation for the expanded site.
46
+
47
+ ## [0.2.0] - 2026-03-06
48
+
49
+ ### Added
50
+
51
+ - Added the initial Python package for validating CWL workflow inputs from embedded assertion hints.
52
+ - Added support for `eoap:JSONSchemaHint`, `eoap:RegoPolicyHint`, and `eoap:Cql2FilterHint`.
53
+ - Added the `assertions-mate` command-line entry point for loading CWL workflows, reading YAML inputs, and reporting validation violations.
54
+ - Added CWL schema definitions for the supported assertion hint records.
55
+ - Added Pydantic error models for validation problem details and business rule violations.
56
+ - Added unit tests for JSON Schema, Rego, CQL2, and hint extraction behavior.
57
+ - Added README usage documentation, notebooks, and the initial MkDocs documentation setup.
58
+ - Added Hatch, pytest, Ruff, Taskfile, and CI configuration for development and validation workflows.
59
+ - Added Apache-2.0 license headers across the package.
60
+
61
+ ### Changed
62
+
63
+ - Updated workflow CI to use Python 3.12 and then expanded the test matrix across Python 3.10 through 3.14.
64
+ - Aligned hint keyword naming and schema structure with CWL/EOAP conventions.
65
+
66
+ ### Fixed
67
+
68
+ - Fixed documentation build issues around PlantUML and MkDocs plugin configuration.
69
+ - Fixed API documentation generation and schema behavior according to canonical CWL practices.
70
+
71
+ [Unreleased]: https://github.com/Terradue/assertions-mate/compare/v0.4.0...develop
72
+ [0.4.0]: https://github.com/Terradue/assertions-mate/compare/v0.2.0...v0.4.0
73
+ [0.2.0]: https://github.com/Terradue/assertions-mate/releases/tag/v0.2.0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: assertions-mate
3
- Version: 0.2.0
3
+ Version: 0.5.0
4
4
  Project-URL: Documentation, https://github.com/Terradue/assertions-mate#README.md
5
5
  Project-URL: Issues, https://github.com/Terradue/assertions-mate/issues
6
6
  Project-URL: Source, https://github.com/Terradue/assertions-mate
@@ -18,17 +18,15 @@ Classifier: Programming Language :: Python :: 3.14
18
18
  Classifier: Programming Language :: Python :: Implementation :: CPython
19
19
  Classifier: Programming Language :: Python :: Implementation :: PyPy
20
20
  Requires-Python: >=3.10
21
- Requires-Dist: click
22
- Requires-Dist: cwl-utils
23
- Requires-Dist: cwl2ogc>=0.10.0
24
- Requires-Dist: jsonschema
25
- Requires-Dist: loguru
26
- Requires-Dist: pydantic
27
- Requires-Dist: pygeofilter
28
- Requires-Dist: pygeofilter[backend-native]
29
- Requires-Dist: pystac-client
21
+ Requires-Dist: click==8.3.3
22
+ Requires-Dist: cwl-utils==0.41
23
+ Requires-Dist: cwl2ogc==0.18.0
24
+ Requires-Dist: jsonschema==4.26.0
25
+ Requires-Dist: loguru==0.7.3
26
+ Requires-Dist: pydantic==2.12.5
27
+ Requires-Dist: pygeofilter[backend-native]==0.3.3
28
+ Requires-Dist: pyyaml==6.0.3
30
29
  Requires-Dist: regopy==0.4.6
31
- Requires-Dist: shapely
32
30
  Description-Content-Type: text/markdown
33
31
 
34
32
  # Assertions Mate
@@ -42,6 +40,12 @@ It adds policy and rule checks on top of CWL typing by supporting:
42
40
 
43
41
  Documentation site: https://terradue.github.io/assertions-mate/
44
42
 
43
+ Documentation follows the Diataxis framework:
44
+ - Tutorials: learning-oriented walkthroughs
45
+ - How-to guides: task-focused recipes
46
+ - Reference: technical contracts and interfaces
47
+ - Explanation: design rationale and concepts
48
+
45
49
  ## Why Use It
46
50
 
47
51
  When a CWL workflow needs stricter runtime checks (business rules, policy constraints, geospatial conditions), `assertions-mate` lets you define them as workflow hints and evaluate them against an input payload before execution.
@@ -9,6 +9,12 @@ It adds policy and rule checks on top of CWL typing by supporting:
9
9
 
10
10
  Documentation site: https://terradue.github.io/assertions-mate/
11
11
 
12
+ Documentation follows the Diataxis framework:
13
+ - Tutorials: learning-oriented walkthroughs
14
+ - How-to guides: task-focused recipes
15
+ - Reference: technical contracts and interfaces
16
+ - Explanation: design rationale and concepts
17
+
12
18
  ## Why Use It
13
19
 
14
20
  When a CWL workflow needs stricter runtime checks (business rules, policy constraints, geospatial conditions), `assertions-mate` lets you define them as workflow hints and evaluate them against an input payload before execution.
@@ -0,0 +1,46 @@
1
+ # Copyright 2026 Terradue
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+
15
+ version: '3'
16
+
17
+ includes:
18
+ quality: https://raw.githubusercontent.com/Terradue/taskfile-utils/refs/heads/main/quality.yaml
19
+
20
+ tasks:
21
+
22
+ default:
23
+ cmds:
24
+ - task: quality:test
25
+ - task: quality:check
26
+
27
+ generate_schema_doc:
28
+ cmds:
29
+ - |
30
+ uv run \
31
+ --no-cache \
32
+ --no-project \
33
+ --with schema-salad \
34
+ schema-salad-doc \
35
+ --only 'http://oeap.github.io/schema#JSONSchemaHint' \
36
+ --only 'http://oeap.github.io/schema#RegoPolicyHint' \
37
+ --only 'http://oeap.github.io/schema#Cql2Query' \
38
+ --only 'http://oeap.github.io/schema#Cql2FilterHint' \
39
+ ./schemas/hints.yaml > ./docs/reference/hints_schema.html
40
+
41
+ docs:serve:
42
+ desc: "Serve MkDocs site using hatch docs environment"
43
+ cmds:
44
+ - |
45
+ set -euo pipefail
46
+ HATCH_DATA_DIR="$PWD/.task/hatch" hatch run docs:serve
@@ -0,0 +1,66 @@
1
+ # Architecture and Design
2
+
3
+ `assertions-mate` is built around hint-driven validation for CWL workflows.
4
+
5
+ ## Why Hints
6
+
7
+ CWL input typing can enforce structure, but many operational constraints are semantic:
8
+ - policy constraints
9
+ - domain rules
10
+ - geospatial relationships
11
+
12
+ Hints let these constraints travel with workflow definitions and be checked consistently before runtime.
13
+
14
+ ## Validation Flow
15
+
16
+ 1. Load CWL workflow document(s).
17
+ 2. Read `workflow.hints`.
18
+ 3. Map supported `eoap:*` hint classes to typed hint models.
19
+ 4. Build validator objects from hints.
20
+ 5. Run each validator against provided inputs.
21
+ 6. Aggregate and log violations.
22
+
23
+ ## Execution Semantics
24
+
25
+ `assertions-mate` follows a best-effort setup model:
26
+
27
+ - each hint is mapped and initialized independently
28
+ - setup failures for one hint do not prevent other hints from running
29
+ - validation output is therefore partial if one validator fails to initialize
30
+
31
+ This model favors operational continuity and progressive validation.
32
+
33
+ ## Validator Model
34
+
35
+ Each hint type is responsible for producing a validator via `.validator()`.
36
+
37
+ This keeps:
38
+ - hint parsing and serialization concerns in hint models
39
+ - runtime validation behavior in validator classes
40
+
41
+ ## Input Shape and Key Resolution
42
+
43
+ Validators operate on the loaded input mapping as-is.
44
+
45
+ Implications:
46
+ - input keys must match workflow input names exactly
47
+ - object wrappers such as `value` must be handled explicitly in rules (for example in Rego)
48
+ - inconsistent shape across workflows can produce false negatives if rules target the wrong path
49
+
50
+ ## Supported Rule Languages
51
+
52
+ - JSON Schema: structural constraints over payload shape and values
53
+ - Rego: policy-oriented queries and rich rule composition
54
+ - CQL2: declarative predicate checks, including geospatial expressions
55
+
56
+ ## Reliability Tradeoffs
57
+
58
+ - Strength: multi-validator execution can still produce useful checks when one hint fails setup.
59
+ - Tradeoff: setup errors and runtime backend constraints may reduce total coverage for a given run.
60
+ - Practical guidance: treat logs as part of the contract and monitor setup failures explicitly in CI.
61
+
62
+ ## Known Gaps and Improvement Areas
63
+
64
+ - Runtime-specific parser differences can affect CWL load behavior and Rego syntax support.
65
+ - Some CQL2 features require explicit coercion helpers (`ensure_spatial`, `ensure_bbox`).
66
+ - Strict fail-fast exit semantics for reported violations are not yet guaranteed in all execution paths.
@@ -0,0 +1,40 @@
1
+ # Compatibility and Limitations
2
+
3
+ This page explains where runtime behavior depends on parser and backend versions.
4
+
5
+ ## Rego Runtime Coupling
6
+
7
+ Rego syntax support is runtime-dependent.
8
+
9
+ Stable pattern in current examples:
10
+
11
+ ```rego
12
+ deny[msg] {
13
+ condition
14
+ msg := "..."
15
+ }
16
+ ```
17
+
18
+ Depending on runtime, newer syntax forms can fail with parser errors such as `Invalid literal`.
19
+
20
+ ## CQL2 Backend Constraints
21
+
22
+ CQL2 spatial predicates operate reliably when payloads are coerced with helper functions:
23
+
24
+ - `ensure_spatial(...)` for GeoJSON geometry objects
25
+
26
+ Without coercion, backend exceptions can occur because predicates receive non-geometry objects.
27
+
28
+ ## External CWL Type References
29
+
30
+ External schema refs (for example EOAP `#DateTime`, `#Polygon`) may require online resolution and parser compatibility.
31
+
32
+ Operational impact:
33
+ - local/offline environments may fail to resolve external refs
34
+ - integration tests should allow offline skip behavior
35
+
36
+ ## JSON CQL2 From YAML
37
+
38
+ YAML-native scalar wrappers can affect CQL2 JSON evaluation if not normalized.
39
+
40
+ Current validator behavior includes normalization to builtin Python values before parsing CQL2 JSON, improving reliability.
@@ -0,0 +1,32 @@
1
+ # Testing and Reliability
2
+
3
+ This project benefits from a split testing strategy.
4
+
5
+ ## Unit Tests
6
+
7
+ Focus on deterministic behavior with local types and direct validator logic.
8
+
9
+ Examples:
10
+ - hint extraction and mapping tests
11
+ - CQL2 text/json predicate tests
12
+ - JSON schema validation tests
13
+
14
+ ## Integration-Oriented Tests
15
+
16
+ Use real example workflows and external type references.
17
+
18
+ Because these can require network and parser compatibility, they should:
19
+ - skip when offline
20
+ - be isolated from core deterministic tests
21
+
22
+ ## Reliability Patterns for CI
23
+
24
+ - treat hint setup errors as first-class signals
25
+ - include at least one valid and one invalid case per how-to example
26
+ - prefer stable syntax subsets for Rego and CQL2 in production pipelines
27
+
28
+ ## Practical Guardrails
29
+
30
+ - keep payload key names aligned with workflow inputs
31
+ - document scalar vs wrapped object shapes (`value`) and test both where applicable
32
+ - reuse proven example expressions to avoid backend incompatibilities
@@ -0,0 +1,57 @@
1
+ # How-to: Add `polygon_area(...)` to the CQL2 Evaluator
2
+
3
+ This guide shows how to extend `assertions-mate` so CQL2 rules can compare polygon area against a fixed threshold.
4
+
5
+ ## Goal
6
+
7
+ Enable expressions like:
8
+
9
+ ```text
10
+ polygon_area(aoi) < 1000
11
+ ```
12
+
13
+ ## 1. Define the new function in a CQL2 hint
14
+
15
+ In your workflow hints, plug the suggested implementation:
16
+
17
+ ```yaml
18
+ hints:
19
+ - class: eoap:Cql2FilterHint
20
+ custom_functions: |
21
+ from shapely import geometry
22
+ from typing import Any, List, Mapping, Union
23
+
24
+ def polygon_area(input: Union[Mapping[str, Any], List[Any]]):
25
+ """Return area for a GeoJSON Polygon payload or raw coordinates list."""
26
+ if isinstance(input, dict):
27
+ geo_type = input.get("type")
28
+ coords = input.get("coordinates")
29
+ if geo_type != "Polygon" or not coords:
30
+ raise ValueError("Input must be a GeoJSON Polygon with coordinates")
31
+ geom = geometry.Polygon(coords[0])
32
+ return geom.area
33
+
34
+ if isinstance(input, list):
35
+ geom = geometry.Polygon(input[0] if input and isinstance(input[0], list) else input)
36
+ return geom.area
37
+
38
+ raise ValueError(f"Unsupported polygon input type: {type(input)}")
39
+ queries:
40
+ - id: aoi-area-limit
41
+ cql2: "polygon_area(aoi) < 1000"
42
+ message: "AOI area must be smaller than 1000"
43
+ ```
44
+
45
+ ## 2. Validate with CLI
46
+
47
+ ```bash
48
+ assertions-mate path/to/workflow.cwl --inputs path/to/inputs.yaml
49
+ ```
50
+
51
+ ## Notes on units
52
+
53
+ If AOI coordinates are lon/lat (EPSG:4326), `polygon_area` from Shapely returns degree-squared values, not square meters.
54
+
55
+ For metric thresholds, either:
56
+ - reproject geometry before computing area
57
+ - or compute geodesic area with a dedicated geodesic approach
@@ -0,0 +1,46 @@
1
+ # How-to: Author CQL2 Rules in JSON Encoding
2
+
3
+ You can provide `cql2` as JSON, not only text.
4
+
5
+ ## 1. Define the input
6
+
7
+ ```yaml
8
+ inputs:
9
+ mode:
10
+ type: string
11
+ ```
12
+
13
+ ## 2. Add CQL2 JSON rule
14
+
15
+ ```yaml
16
+ hints:
17
+ - class: eoap:Cql2FilterHint
18
+ queries:
19
+ - id: mode-is-strict
20
+ cql2:
21
+ op: "="
22
+ args:
23
+ - property: mode
24
+ - "strict"
25
+ message: "mode must be strict"
26
+ ```
27
+
28
+ ## 3. Validate with sample values
29
+
30
+ Valid:
31
+
32
+ ```yaml
33
+ mode: "strict"
34
+ ```
35
+
36
+ Run:
37
+
38
+ ```bash
39
+ assertions-mate workflow.cwl --inputs inputs-valid.yaml
40
+ ```
41
+
42
+ ## Ready-to-run example in this repository
43
+
44
+ - `examples/cql2-json-validation/workflow.cwl`
45
+ - `examples/cql2-json-validation/inputs-valid.yaml`
46
+ - `examples/cql2-json-validation/inputs-invalid.yaml`
@@ -0,0 +1,57 @@
1
+ # How-to: Combine Multiple Hints in One Workflow
2
+
3
+ Use `JSONSchemaHint`, `RegoPolicyHint`, and `Cql2FilterHint` together to enforce structure, policy, and spatial predicates.
4
+
5
+ ## 1. Define the inputs
6
+
7
+ ```yaml
8
+ inputs:
9
+ count:
10
+ type: int
11
+ aoi:
12
+ type: https://raw.githubusercontent.com/eoap/schemas/main/geojson.yaml#Polygon
13
+ candidate:
14
+ type: https://raw.githubusercontent.com/eoap/schemas/main/geojson.yaml#Polygon
15
+ ```
16
+
17
+ ## 2. Add multiple hints
18
+
19
+ ```yaml
20
+ hints:
21
+ - class: eoap:JSONSchemaHint
22
+ json_schema:
23
+ type: object
24
+ required: [count, aoi, candidate]
25
+ properties:
26
+ count:
27
+ type: integer
28
+ minimum: 1
29
+ - class: eoap:RegoPolicyHint
30
+ module: |
31
+ package workflow
32
+ deny[msg] {
33
+ input["count"] > 10
34
+ msg := "count must be <= 10"
35
+ }
36
+ queries:
37
+ - data.workflow.deny[_]
38
+ - class: eoap:Cql2FilterHint
39
+ queries:
40
+ - id: spatial-check
41
+ cql2: "s_intersects(ensure_spatial(candidate), ensure_spatial(aoi))"
42
+ message: "candidate must intersect aoi"
43
+ ```
44
+
45
+ ## 3. Validate with sample values
46
+
47
+ Run:
48
+
49
+ ```bash
50
+ assertions-mate workflow.cwl --inputs inputs-valid.yaml
51
+ ```
52
+
53
+ ## Ready-to-run example in this repository
54
+
55
+ - `examples/multi-hint-validation/workflow.cwl`
56
+ - `examples/multi-hint-validation/inputs-valid.yaml`
57
+ - `examples/multi-hint-validation/inputs-invalid.yaml`
@@ -0,0 +1,52 @@
1
+ # How-to: Create Reusable Rego Snippets
2
+
3
+ Keep common checks reusable by copying a shared module block between workflows.
4
+
5
+ ## 1. Define the inputs
6
+
7
+ ```yaml
8
+ inputs:
9
+ start-date:
10
+ type: string
11
+ end-date:
12
+ type: string
13
+ ```
14
+
15
+ ## 2. Add reusable Rego helper
16
+
17
+ ```rego
18
+ package workflow
19
+
20
+ is_rfc3339_utc(s) {
21
+ regex.match("^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}Z$", s)
22
+ }
23
+ ```
24
+
25
+ Then reuse in multiple deny rules.
26
+
27
+ ## 3. Add hint using the helper
28
+
29
+ ```yaml
30
+ hints:
31
+ - class: eoap:RegoPolicyHint
32
+ module: |
33
+ package workflow
34
+
35
+ is_rfc3339_utc(s) {
36
+ regex.match("^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}Z$", s)
37
+ }
38
+
39
+ deny[msg] {
40
+ s := input["start-date"]
41
+ not is_rfc3339_utc(s)
42
+ msg := "start-date format is invalid"
43
+ }
44
+ queries:
45
+ - data.workflow.deny[_]
46
+ ```
47
+
48
+ ## Ready-to-run example in this repository
49
+
50
+ - `examples/reusable-rego-snippets/workflow.cwl`
51
+ - `examples/reusable-rego-snippets/inputs-valid.yaml`
52
+ - `examples/reusable-rego-snippets/inputs-invalid.yaml`
@@ -0,0 +1,27 @@
1
+ # How-to: Test Hints With pytest
2
+
3
+ Use direct validator classes in unit tests for quick feedback.
4
+
5
+ ## 1. Create a validator test
6
+
7
+ ```python
8
+ from assertions_mate import Cql2Query
9
+ from assertions_mate.cql2_validator import Cql2Validator
10
+
11
+ def test_rule_fails_when_count_not_positive():
12
+ validator = Cql2Validator(
13
+ queries=[Cql2Query(id="q", cql2="count > 0", message="count must be positive")]
14
+ )
15
+ result = validator.validate_inputs({"count": 0})
16
+ assert result is not None
17
+ ```
18
+
19
+ ## 2. Run the test
20
+
21
+ ```bash
22
+ hatch run test:test-q examples/pytest-validation/test_validators_example.py
23
+ ```
24
+
25
+ ## Ready-to-run example in this repository
26
+
27
+ - `examples/pytest-validation/test_validators_example.py`
@@ -0,0 +1,19 @@
1
+ # How-to: Troubleshoot CWL Loader Errors
2
+
3
+ When validation fails before hints execute, the CWL document may be rejected by `cwl_utils`.
4
+
5
+ ## Common symptom
6
+
7
+ - `schema_salad.exceptions.ValidationException`
8
+ - messages around invalid `requirements` field shape
9
+
10
+ ## Checklist
11
+
12
+ 1. Start with a minimal single-workflow document (`class: Workflow`, `cwlVersion: v1.2`).
13
+ 2. Add one input at a time and re-run.
14
+ 3. If failures appear after adding `requirements`, temporarily remove that section to isolate parser compatibility.
15
+ 4. Keep examples runnable first; reintroduce advanced schema refs after parser behavior is confirmed.
16
+
17
+ ## Tip
18
+
19
+ Different environments can parse the same CWL differently depending on exact `cwl_utils` and schema-salad versions.
@@ -0,0 +1,32 @@
1
+ # How-to: Troubleshoot Rego "Invalid literal" Errors
2
+
3
+ If you see errors around `deny contains ... if { ... }`, your runtime is parsing classic Rego syntax.
4
+
5
+ ## Symptoms
6
+
7
+ - `Invalid literal`
8
+ - `wellformed_error`
9
+ - validator setup fails for `RegoPolicyHint`
10
+
11
+ ## Fix
12
+
13
+ Use classic syntax:
14
+
15
+ ```rego
16
+ deny[msg] {
17
+ input["x"] == null
18
+ msg := "x is required"
19
+ }
20
+ ```
21
+
22
+ instead of:
23
+
24
+ ```rego
25
+ deny contains "x is required" if {
26
+ input["x"] == null
27
+ }
28
+ ```
29
+
30
+ ## Verify
31
+
32
+ Run your workflow and ensure `Setting up validator for RegoPolicyHint...` completes without parser errors.
@@ -0,0 +1,28 @@
1
+ # How-to: Use Packed CWL vs Single Workflow CWL
2
+
3
+ ## Single workflow
4
+
5
+ Best for local examples and fast validation loops.
6
+
7
+ ```yaml
8
+ cwlVersion: v1.2
9
+ class: Workflow
10
+ id: my-workflow
11
+ ...
12
+ ```
13
+
14
+ ## Packed workflow (`$graph`)
15
+
16
+ Useful when distributing multiple process definitions in one file.
17
+
18
+ ```yaml
19
+ cwlVersion: v1.2
20
+ $graph:
21
+ - class: Workflow
22
+ id: my-workflow
23
+ ...
24
+ ```
25
+
26
+ ## Recommendation
27
+
28
+ Start with single-workflow CWL for validator docs/examples, then move to packed CWL once parser compatibility is confirmed in your target runtime.