aeo-validator-service 0.1.1__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.
@@ -0,0 +1,41 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+
9
+ jobs:
10
+ test:
11
+ name: test (py${{ matrix.python-version }})
12
+ runs-on: ubuntu-latest
13
+ strategy:
14
+ fail-fast: false
15
+ matrix:
16
+ python-version: ["3.11", "3.12", "3.13"]
17
+ steps:
18
+ - uses: actions/checkout@v4
19
+
20
+ - name: Set up Python
21
+ uses: actions/setup-python@v5
22
+ with:
23
+ python-version: ${{ matrix.python-version }}
24
+ cache: pip
25
+
26
+ - name: Install
27
+ run: |
28
+ python -m pip install --upgrade pip
29
+ pip install -e ".[dev]"
30
+
31
+ - name: Lint
32
+ run: ruff check src tests
33
+
34
+ - name: Format check
35
+ run: ruff format --check src tests
36
+
37
+ - name: Type check
38
+ run: mypy src
39
+
40
+ - name: Test
41
+ run: pytest -v
@@ -0,0 +1,35 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ push:
5
+ tags: ["v*"]
6
+
7
+ jobs:
8
+ publish:
9
+ name: Build + publish wheel + sdist
10
+ runs-on: ubuntu-latest
11
+ environment:
12
+ name: pypi
13
+ url: https://pypi.org/p/aeo-validator-service
14
+ permissions:
15
+ id-token: write
16
+ contents: read
17
+ steps:
18
+ - uses: actions/checkout@v4
19
+ with:
20
+ fetch-depth: 0
21
+ - uses: actions/setup-python@v5
22
+ with:
23
+ python-version: "3.13"
24
+ - name: Install build tools
25
+ run: |
26
+ python -m pip install --upgrade pip
27
+ python -m pip install build
28
+ - name: Build distributions
29
+ run: python -m build
30
+ - name: Inspect distributions
31
+ run: ls -la dist/
32
+ - name: Publish to PyPI
33
+ uses: pypa/gh-action-pypi-publish@release/v1
34
+ with:
35
+ attestations: true
@@ -0,0 +1,12 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ *.egg-info/
4
+ .venv/
5
+ .pytest_cache/
6
+ .ruff_cache/
7
+ .mypy_cache/
8
+ dist/
9
+ build/
10
+ .coverage
11
+ htmlcov/
12
+ .DS_Store
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Miz Causevic / Kinetic Gain
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,193 @@
1
+ Metadata-Version: 2.4
2
+ Name: aeo-validator-service
3
+ Version: 0.1.1
4
+ Summary: Always-on validator service for AEO + Kinetic Gain Protocol Suite documents. Validate by URL, track content-hash drift, schedule re-fetch, emit structured diffs. The fourth layer of the AEO Reference Stack. Optional audit-stream-py integration via AUDIT_STREAM_URL env var.
5
+ Project-URL: Homepage, https://github.com/mizcausevic-dev/aeo-validator-service
6
+ Project-URL: Repository, https://github.com/mizcausevic-dev/aeo-validator-service
7
+ Project-URL: Issues, https://github.com/mizcausevic-dev/aeo-validator-service/issues
8
+ Project-URL: AEO Spec, https://github.com/mizcausevic-dev/aeo-protocol-spec
9
+ Project-URL: Author Site, https://kineticgain.com/
10
+ Author-email: Miz Causevic <miz@kineticgain.com>
11
+ License: MIT
12
+ License-File: LICENSE
13
+ Keywords: aeo,drift,fastapi,kinetic-gain-protocol-suite,validator
14
+ Classifier: Development Status :: 4 - Beta
15
+ Classifier: Framework :: FastAPI
16
+ Classifier: Intended Audience :: Developers
17
+ Classifier: License :: OSI Approved :: MIT License
18
+ Classifier: Operating System :: OS Independent
19
+ Classifier: Programming Language :: Python :: 3
20
+ Classifier: Programming Language :: Python :: 3.11
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Programming Language :: Python :: 3.13
23
+ Classifier: Topic :: Software Development :: Libraries
24
+ Classifier: Topic :: System :: Monitoring
25
+ Classifier: Typing :: Typed
26
+ Requires-Python: >=3.11
27
+ Requires-Dist: fastapi>=0.115
28
+ Requires-Dist: httpx>=0.27
29
+ Requires-Dist: pydantic>=2.7
30
+ Requires-Dist: uvicorn[standard]>=0.30
31
+ Provides-Extra: dev
32
+ Requires-Dist: mypy>=1.11; extra == 'dev'
33
+ Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
34
+ Requires-Dist: pytest>=8.2; extra == 'dev'
35
+ Requires-Dist: ruff>=0.6; extra == 'dev'
36
+ Description-Content-Type: text/markdown
37
+
38
+ # aeo-validator-service
39
+
40
+ [![CI](https://github.com/mizcausevic-dev/aeo-validator-service/actions/workflows/ci.yml/badge.svg)](https://github.com/mizcausevic-dev/aeo-validator-service/actions/workflows/ci.yml)
41
+ [![Python](https://img.shields.io/badge/python-3.11%20%7C%203.12%20%7C%203.13-blue)](https://www.python.org/)
42
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
43
+
44
+ **Always-on validator service for AEO and the rest of the Kinetic Gain Protocol Suite.** Fetches a vendor URL, validates the document against the right spec (sniffed from `*_version`), hashes it canonically, and tracks **drift** across re-checks. The fourth layer of the AEO Reference Stack — what the CLI is, but always running, with history.
45
+
46
+ ```
47
+ 1. SDKs aeo-sdk-python / -typescript / -rust / -go / -swift
48
+ 2. CLI aeo-cli
49
+ 3. Crawler aeo-crawler
50
+ 4. Validator service <- this repo
51
+ ```
52
+
53
+ ---
54
+
55
+ ## Why a service instead of just the CLI
56
+
57
+ The CLI answers "is this doc valid right now." That's enough on a developer laptop. In production you want three more things:
58
+
59
+ 1. **HTTP for non-Python services.** The CLI is Python-only. The service is a curl away.
60
+ 2. **Drift over time.** Hash a vendor's AEO doc today, hash it again tomorrow, and tell me what changed. Not just "different" — *which field* changed. That's the signal that something's worth a Slack ping.
61
+ 3. **Watches.** "Check this URL every hour and let me know when it goes invalid or its spec changes." The service holds the history so the diff has somewhere to anchor.
62
+
63
+ ---
64
+
65
+ ## Install
66
+
67
+ ```bash
68
+ pip install aeo-validator-service
69
+ aeo-validator-service # binds 0.0.0.0:8091
70
+ ```
71
+
72
+ Python 3.11+. Runtime deps: `fastapi`, `httpx`, `pydantic`, `uvicorn`.
73
+
74
+ ---
75
+
76
+ ## Endpoints
77
+
78
+ | Method | Path | What it does |
79
+ | --- | --- | --- |
80
+ | GET | `/` | Service info + supported spec list. |
81
+ | GET | `/healthz` | Liveness probe. |
82
+ | POST | `/validate/by-url` | Fetch + validate by URL. One-shot, no watch. |
83
+ | POST | `/validate/inline` | Validate an already-fetched document — no network. |
84
+ | POST | `/watches` | Create a persistent watch for a URL; the initial fetch + validation runs synchronously. |
85
+ | GET | `/watches` | List watch IDs. |
86
+ | GET | `/watches/{id}` | Watch metadata + last result. |
87
+ | GET | `/watches/{id}/history` | Full validation history (oldest → newest). |
88
+ | POST | `/watches/{id}/recheck` | Re-fetch + validate. Returns a structured **DriftReport** vs. the previous result. |
89
+ | DELETE | `/watches/{id}` | Delete the watch. |
90
+
91
+ ---
92
+
93
+ ## Supported specs
94
+
95
+ The validator sniffs the spec kind from the top-level `*_version` field — the same trick the [unified visualizer](https://github.com/mizcausevic-dev/kinetic-gain-visualizer) uses. Eleven specs auto-detected:
96
+
97
+ | Spec | Detected via |
98
+ | --- | --- |
99
+ | AEO Protocol | `aeo_version` |
100
+ | Prompt Provenance | `provenance_version` |
101
+ | Agent Cards | `agent_card_version` |
102
+ | AI Evidence Format | `evidence_version` |
103
+ | MCP Tool Cards | `tool_card_version` |
104
+ | AI Tutor Cards | `tutor_card_version` |
105
+ | Student AI Disclosure | `disclosure_version` |
106
+ | Classroom AI AUP | `aup_version` |
107
+ | Clinical AI Disclosure | `clinical_ai_card_version` |
108
+ | AI Incident Card | `incident_card_version` |
109
+ | AI Procurement Decision Card | `decision_card_version` |
110
+
111
+ For each one the validator runs:
112
+
113
+ - **Universal checks** — version field present, non-blank
114
+ - **Spec-specific smoke checks** — AEO entity has `id` + `type` + `name`; agent-card has `agent_id` + `capabilities`; decision-card with `approved-with-conditions` requires non-empty `conditions[]`; etc.
115
+
116
+ This isn't a full Schema validator — punt to the SDKs when every-field-typed validation is needed. The point of *this* layer is "does it look right at a glance" plus drift tracking.
117
+
118
+ ---
119
+
120
+ ## Drift report
121
+
122
+ ```json
123
+ {
124
+ "url": "https://acme.example/.well-known/aeo.json",
125
+ "drifted": true,
126
+ "spec_changed": false,
127
+ "became_invalid": false,
128
+ "became_valid": false,
129
+ "content_hash_before": "sha256:9a3f...",
130
+ "content_hash_after": "sha256:b7d1...",
131
+ "added_fields": ["claims"],
132
+ "removed_fields": [],
133
+ "changed_fields": ["entity"],
134
+ "before_issues": 0,
135
+ "after_issues": 0
136
+ }
137
+ ```
138
+
139
+ A drift is *any* of: hash changed, spec kind changed, validity flipped, or top-level field set changed. Webhooks-on-drift are an obvious follow-up (PR welcome).
140
+
141
+ ---
142
+
143
+ ## Quick start
144
+
145
+ ```bash
146
+ # One-shot validation:
147
+ curl -X POST http://localhost:8091/validate/by-url \
148
+ -H 'Content-Type: application/json' \
149
+ -d '{"url": "https://acme.example/.well-known/aeo.json", "include_body": true}'
150
+
151
+ # Persistent watch:
152
+ curl -X POST http://localhost:8091/watches \
153
+ -H 'Content-Type: application/json' \
154
+ -d '{"url": "https://acme.example/.well-known/aeo.json"}'
155
+ # -> {"watch_id": "a1b2c3", ...}
156
+
157
+ # Some time later — re-check and see what changed:
158
+ curl -X POST http://localhost:8091/watches/a1b2c3/recheck
159
+ ```
160
+
161
+ ---
162
+
163
+ ## Hashing convention
164
+
165
+ `content_hash` is `sha256:<hex>` over canonical JSON — sorted keys, no whitespace, UTF-8. Same convention as [`procurement-decision-api`](https://github.com/mizcausevic-dev/procurement-decision-api), so the two services produce **identical** `content_hash` values for identical documents.
166
+
167
+ ---
168
+
169
+ ## Tests
170
+
171
+ ```bash
172
+ pip install -e ".[dev]"
173
+ ruff check src tests && ruff format --check src tests
174
+ mypy src
175
+ pytest -v
176
+ ```
177
+
178
+ Test fixtures use `httpx.MockTransport` so nothing touches the network. CI matrix Python 3.11 / 3.12 / 3.13.
179
+
180
+ ---
181
+
182
+ ## Related in this ecosystem
183
+
184
+ - **[aeo-protocol-spec](https://github.com/mizcausevic-dev/aeo-protocol-spec)** — the spec this service validates.
185
+ - **[aeo-cli](https://github.com/mizcausevic-dev/aeo-cli)** · **[aeo-crawler](https://github.com/mizcausevic-dev/aeo-crawler)** — layers 2 and 3 of the AEO Reference Stack.
186
+ - **[procurement-decision-api](https://github.com/mizcausevic-dev/procurement-decision-api)** — uses the same canonical-hash convention; the two pair naturally.
187
+ - More at [kineticgain.com](https://kineticgain.com/).
188
+
189
+ ---
190
+
191
+ ## License
192
+
193
+ MIT. See [LICENSE](LICENSE).
@@ -0,0 +1,156 @@
1
+ # aeo-validator-service
2
+
3
+ [![CI](https://github.com/mizcausevic-dev/aeo-validator-service/actions/workflows/ci.yml/badge.svg)](https://github.com/mizcausevic-dev/aeo-validator-service/actions/workflows/ci.yml)
4
+ [![Python](https://img.shields.io/badge/python-3.11%20%7C%203.12%20%7C%203.13-blue)](https://www.python.org/)
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
6
+
7
+ **Always-on validator service for AEO and the rest of the Kinetic Gain Protocol Suite.** Fetches a vendor URL, validates the document against the right spec (sniffed from `*_version`), hashes it canonically, and tracks **drift** across re-checks. The fourth layer of the AEO Reference Stack — what the CLI is, but always running, with history.
8
+
9
+ ```
10
+ 1. SDKs aeo-sdk-python / -typescript / -rust / -go / -swift
11
+ 2. CLI aeo-cli
12
+ 3. Crawler aeo-crawler
13
+ 4. Validator service <- this repo
14
+ ```
15
+
16
+ ---
17
+
18
+ ## Why a service instead of just the CLI
19
+
20
+ The CLI answers "is this doc valid right now." That's enough on a developer laptop. In production you want three more things:
21
+
22
+ 1. **HTTP for non-Python services.** The CLI is Python-only. The service is a curl away.
23
+ 2. **Drift over time.** Hash a vendor's AEO doc today, hash it again tomorrow, and tell me what changed. Not just "different" — *which field* changed. That's the signal that something's worth a Slack ping.
24
+ 3. **Watches.** "Check this URL every hour and let me know when it goes invalid or its spec changes." The service holds the history so the diff has somewhere to anchor.
25
+
26
+ ---
27
+
28
+ ## Install
29
+
30
+ ```bash
31
+ pip install aeo-validator-service
32
+ aeo-validator-service # binds 0.0.0.0:8091
33
+ ```
34
+
35
+ Python 3.11+. Runtime deps: `fastapi`, `httpx`, `pydantic`, `uvicorn`.
36
+
37
+ ---
38
+
39
+ ## Endpoints
40
+
41
+ | Method | Path | What it does |
42
+ | --- | --- | --- |
43
+ | GET | `/` | Service info + supported spec list. |
44
+ | GET | `/healthz` | Liveness probe. |
45
+ | POST | `/validate/by-url` | Fetch + validate by URL. One-shot, no watch. |
46
+ | POST | `/validate/inline` | Validate an already-fetched document — no network. |
47
+ | POST | `/watches` | Create a persistent watch for a URL; the initial fetch + validation runs synchronously. |
48
+ | GET | `/watches` | List watch IDs. |
49
+ | GET | `/watches/{id}` | Watch metadata + last result. |
50
+ | GET | `/watches/{id}/history` | Full validation history (oldest → newest). |
51
+ | POST | `/watches/{id}/recheck` | Re-fetch + validate. Returns a structured **DriftReport** vs. the previous result. |
52
+ | DELETE | `/watches/{id}` | Delete the watch. |
53
+
54
+ ---
55
+
56
+ ## Supported specs
57
+
58
+ The validator sniffs the spec kind from the top-level `*_version` field — the same trick the [unified visualizer](https://github.com/mizcausevic-dev/kinetic-gain-visualizer) uses. Eleven specs auto-detected:
59
+
60
+ | Spec | Detected via |
61
+ | --- | --- |
62
+ | AEO Protocol | `aeo_version` |
63
+ | Prompt Provenance | `provenance_version` |
64
+ | Agent Cards | `agent_card_version` |
65
+ | AI Evidence Format | `evidence_version` |
66
+ | MCP Tool Cards | `tool_card_version` |
67
+ | AI Tutor Cards | `tutor_card_version` |
68
+ | Student AI Disclosure | `disclosure_version` |
69
+ | Classroom AI AUP | `aup_version` |
70
+ | Clinical AI Disclosure | `clinical_ai_card_version` |
71
+ | AI Incident Card | `incident_card_version` |
72
+ | AI Procurement Decision Card | `decision_card_version` |
73
+
74
+ For each one the validator runs:
75
+
76
+ - **Universal checks** — version field present, non-blank
77
+ - **Spec-specific smoke checks** — AEO entity has `id` + `type` + `name`; agent-card has `agent_id` + `capabilities`; decision-card with `approved-with-conditions` requires non-empty `conditions[]`; etc.
78
+
79
+ This isn't a full Schema validator — punt to the SDKs when every-field-typed validation is needed. The point of *this* layer is "does it look right at a glance" plus drift tracking.
80
+
81
+ ---
82
+
83
+ ## Drift report
84
+
85
+ ```json
86
+ {
87
+ "url": "https://acme.example/.well-known/aeo.json",
88
+ "drifted": true,
89
+ "spec_changed": false,
90
+ "became_invalid": false,
91
+ "became_valid": false,
92
+ "content_hash_before": "sha256:9a3f...",
93
+ "content_hash_after": "sha256:b7d1...",
94
+ "added_fields": ["claims"],
95
+ "removed_fields": [],
96
+ "changed_fields": ["entity"],
97
+ "before_issues": 0,
98
+ "after_issues": 0
99
+ }
100
+ ```
101
+
102
+ A drift is *any* of: hash changed, spec kind changed, validity flipped, or top-level field set changed. Webhooks-on-drift are an obvious follow-up (PR welcome).
103
+
104
+ ---
105
+
106
+ ## Quick start
107
+
108
+ ```bash
109
+ # One-shot validation:
110
+ curl -X POST http://localhost:8091/validate/by-url \
111
+ -H 'Content-Type: application/json' \
112
+ -d '{"url": "https://acme.example/.well-known/aeo.json", "include_body": true}'
113
+
114
+ # Persistent watch:
115
+ curl -X POST http://localhost:8091/watches \
116
+ -H 'Content-Type: application/json' \
117
+ -d '{"url": "https://acme.example/.well-known/aeo.json"}'
118
+ # -> {"watch_id": "a1b2c3", ...}
119
+
120
+ # Some time later — re-check and see what changed:
121
+ curl -X POST http://localhost:8091/watches/a1b2c3/recheck
122
+ ```
123
+
124
+ ---
125
+
126
+ ## Hashing convention
127
+
128
+ `content_hash` is `sha256:<hex>` over canonical JSON — sorted keys, no whitespace, UTF-8. Same convention as [`procurement-decision-api`](https://github.com/mizcausevic-dev/procurement-decision-api), so the two services produce **identical** `content_hash` values for identical documents.
129
+
130
+ ---
131
+
132
+ ## Tests
133
+
134
+ ```bash
135
+ pip install -e ".[dev]"
136
+ ruff check src tests && ruff format --check src tests
137
+ mypy src
138
+ pytest -v
139
+ ```
140
+
141
+ Test fixtures use `httpx.MockTransport` so nothing touches the network. CI matrix Python 3.11 / 3.12 / 3.13.
142
+
143
+ ---
144
+
145
+ ## Related in this ecosystem
146
+
147
+ - **[aeo-protocol-spec](https://github.com/mizcausevic-dev/aeo-protocol-spec)** — the spec this service validates.
148
+ - **[aeo-cli](https://github.com/mizcausevic-dev/aeo-cli)** · **[aeo-crawler](https://github.com/mizcausevic-dev/aeo-crawler)** — layers 2 and 3 of the AEO Reference Stack.
149
+ - **[procurement-decision-api](https://github.com/mizcausevic-dev/procurement-decision-api)** — uses the same canonical-hash convention; the two pair naturally.
150
+ - More at [kineticgain.com](https://kineticgain.com/).
151
+
152
+ ---
153
+
154
+ ## License
155
+
156
+ MIT. See [LICENSE](LICENSE).
@@ -0,0 +1,79 @@
1
+ [build-system]
2
+ requires = ["hatchling>=1.25"]
3
+ build-backend = "hatchling.build"
4
+
5
+ [project]
6
+ name = "aeo-validator-service"
7
+ version = "0.1.1"
8
+ description = "Always-on validator service for AEO + Kinetic Gain Protocol Suite documents. Validate by URL, track content-hash drift, schedule re-fetch, emit structured diffs. The fourth layer of the AEO Reference Stack. Optional audit-stream-py integration via AUDIT_STREAM_URL env var."
9
+ readme = "README.md"
10
+ license = { text = "MIT" }
11
+ requires-python = ">=3.11"
12
+ authors = [
13
+ { name = "Miz Causevic", email = "miz@kineticgain.com" },
14
+ ]
15
+ keywords = ["aeo", "validator", "drift", "fastapi", "kinetic-gain-protocol-suite"]
16
+ classifiers = [
17
+ "Development Status :: 4 - Beta",
18
+ "Framework :: FastAPI",
19
+ "Intended Audience :: Developers",
20
+ "License :: OSI Approved :: MIT License",
21
+ "Operating System :: OS Independent",
22
+ "Programming Language :: Python :: 3",
23
+ "Programming Language :: Python :: 3.11",
24
+ "Programming Language :: Python :: 3.12",
25
+ "Programming Language :: Python :: 3.13",
26
+ "Topic :: Software Development :: Libraries",
27
+ "Topic :: System :: Monitoring",
28
+ "Typing :: Typed",
29
+ ]
30
+ dependencies = [
31
+ "fastapi>=0.115",
32
+ "httpx>=0.27",
33
+ "pydantic>=2.7",
34
+ "uvicorn[standard]>=0.30",
35
+ ]
36
+
37
+ [project.optional-dependencies]
38
+ dev = [
39
+ "pytest>=8.2",
40
+ "pytest-asyncio>=0.23",
41
+ "ruff>=0.6",
42
+ "mypy>=1.11",
43
+ ]
44
+
45
+ [project.scripts]
46
+ aeo-validator-service = "aeo_validator_service.__main__:main"
47
+
48
+ [project.urls]
49
+ Homepage = "https://github.com/mizcausevic-dev/aeo-validator-service"
50
+ Repository = "https://github.com/mizcausevic-dev/aeo-validator-service"
51
+ Issues = "https://github.com/mizcausevic-dev/aeo-validator-service/issues"
52
+ "AEO Spec" = "https://github.com/mizcausevic-dev/aeo-protocol-spec"
53
+ "Author Site" = "https://kineticgain.com/"
54
+
55
+ [tool.hatch.build.targets.wheel]
56
+ packages = ["src/aeo_validator_service"]
57
+
58
+ [tool.pytest.ini_options]
59
+ testpaths = ["tests"]
60
+ asyncio_mode = "auto"
61
+ filterwarnings = [
62
+ "ignore::DeprecationWarning:starlette.*",
63
+ "ignore::DeprecationWarning:fastapi.*",
64
+ ]
65
+
66
+ [tool.ruff]
67
+ line-length = 110
68
+ target-version = "py311"
69
+
70
+ [tool.ruff.lint]
71
+ select = ["E", "F", "I", "B", "UP", "RUF"]
72
+ ignore = ["E501"]
73
+
74
+ [tool.mypy]
75
+ python_version = "3.11"
76
+ strict = true
77
+ disallow_untyped_defs = true
78
+ warn_unused_ignores = true
79
+ no_implicit_optional = true
@@ -0,0 +1,45 @@
1
+ """
2
+ aeo-validator-service — always-on AEO + Kinetic Gain Protocol Suite validator.
3
+
4
+ The fourth layer of the AEO Reference Stack:
5
+
6
+ 1. SDKs (aeo-sdk-python / -typescript / -rust / -go / -swift)
7
+ 2. CLI (aeo-cli)
8
+ 3. Crawler (aeo-crawler)
9
+ -> 4. Validator service (this repo) — fetches a vendor URL, validates the
10
+ document, hashes it canonically, and tracks drift across check-ins.
11
+
12
+ What the CLI doesn't give you that this service does:
13
+
14
+ - HTTP API for non-Python callers
15
+ - Persistent per-URL history of content_hash + validation_result
16
+ - Drift detection: "did this vendor's AEO change since the last check?"
17
+ - Diff output that points at the field-level change
18
+ - Scheduled re-validation (POST /watches, then GET /watches/{id})
19
+
20
+ The service knows how to validate every spec in the Suite by sniffing the
21
+ top-level `*_version` field, the same trick the unified visualizer uses.
22
+ """
23
+
24
+ from __future__ import annotations
25
+
26
+ from .models import (
27
+ DriftReport,
28
+ SpecKind,
29
+ ValidationIssue,
30
+ ValidationResult,
31
+ Watch,
32
+ )
33
+ from .validator import SuiteValidator
34
+
35
+ __version__ = "0.1.1"
36
+
37
+ __all__ = [
38
+ "DriftReport",
39
+ "SpecKind",
40
+ "SuiteValidator",
41
+ "ValidationIssue",
42
+ "ValidationResult",
43
+ "Watch",
44
+ "__version__",
45
+ ]
@@ -0,0 +1,17 @@
1
+ """Run the API. `python -m aeo_validator_service` or the installed script."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import os
6
+
7
+
8
+ def main() -> None:
9
+ import uvicorn
10
+
11
+ port = int(os.environ.get("PORT", "8091"))
12
+ host = os.environ.get("HOST", "0.0.0.0")
13
+ uvicorn.run("aeo_validator_service.app:app", host=host, port=port, log_level="info")
14
+
15
+
16
+ if __name__ == "__main__":
17
+ main()