payload-heal 0.1.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.
- payload_heal-0.1.0/.github/workflows/ci.yml +33 -0
- payload_heal-0.1.0/.github/workflows/publish.yml +69 -0
- payload_heal-0.1.0/.gitignore +40 -0
- payload_heal-0.1.0/LICENSE +21 -0
- payload_heal-0.1.0/PKG-INFO +288 -0
- payload_heal-0.1.0/README.md +262 -0
- payload_heal-0.1.0/examples/demo_scraper_drift.py +196 -0
- payload_heal-0.1.0/payload_heal/__init__.py +79 -0
- payload_heal-0.1.0/payload_heal/ai_healer.py +227 -0
- payload_heal-0.1.0/payload_heal/cli.py +180 -0
- payload_heal-0.1.0/payload_heal/config.py +92 -0
- payload_heal-0.1.0/payload_heal/heuristics.py +369 -0
- payload_heal-0.1.0/payload_heal/lockfile.py +302 -0
- payload_heal-0.1.0/payload_heal/model.py +256 -0
- payload_heal-0.1.0/payload_heal/notifier.py +86 -0
- payload_heal-0.1.0/payload_heal/skeleton.py +372 -0
- payload_heal-0.1.0/pyproject.toml +56 -0
- payload_heal-0.1.0/tests/__init__.py +1 -0
- payload_heal-0.1.0/tests/test_ai_healer.py +285 -0
- payload_heal-0.1.0/tests/test_cli.py +61 -0
- payload_heal-0.1.0/tests/test_end_to_end.py +199 -0
- payload_heal-0.1.0/tests/test_heuristics.py +249 -0
- payload_heal-0.1.0/tests/test_skeleton_and_lockfile.py +550 -0
|
@@ -0,0 +1,33 @@
|
|
|
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 on Python ${{ matrix.python-version }}
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
strategy:
|
|
14
|
+
matrix:
|
|
15
|
+
python-version: ["3.10", "3.11", "3.12", "3.13"]
|
|
16
|
+
|
|
17
|
+
steps:
|
|
18
|
+
- name: Checkout repository
|
|
19
|
+
uses: actions/checkout@v4
|
|
20
|
+
|
|
21
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
22
|
+
uses: actions/setup-python@v5
|
|
23
|
+
with:
|
|
24
|
+
python-version: ${{ matrix.python-version }}
|
|
25
|
+
cache: "pip"
|
|
26
|
+
|
|
27
|
+
- name: Install package and dependencies
|
|
28
|
+
run: |
|
|
29
|
+
python -m pip install --upgrade pip
|
|
30
|
+
pip install -e .[dev]
|
|
31
|
+
|
|
32
|
+
- name: Run test suite
|
|
33
|
+
run: pytest -v
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types: [published]
|
|
6
|
+
push:
|
|
7
|
+
tags:
|
|
8
|
+
- "v*"
|
|
9
|
+
workflow_dispatch:
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
test:
|
|
13
|
+
name: Run Test Suite
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
strategy:
|
|
16
|
+
matrix:
|
|
17
|
+
python-version: ["3.10", "3.11", "3.12", "3.13"]
|
|
18
|
+
|
|
19
|
+
steps:
|
|
20
|
+
- name: Checkout code
|
|
21
|
+
uses: actions/checkout@v4
|
|
22
|
+
|
|
23
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
24
|
+
uses: actions/setup-python@v5
|
|
25
|
+
with:
|
|
26
|
+
python-version: ${{ matrix.python-version }}
|
|
27
|
+
cache: "pip"
|
|
28
|
+
|
|
29
|
+
- name: Install dependencies
|
|
30
|
+
run: |
|
|
31
|
+
python -m pip install --upgrade pip
|
|
32
|
+
pip install -e .[dev]
|
|
33
|
+
|
|
34
|
+
- name: Run pytest
|
|
35
|
+
run: pytest -v
|
|
36
|
+
|
|
37
|
+
build-and-publish:
|
|
38
|
+
name: Build & Publish to PyPI
|
|
39
|
+
needs: test
|
|
40
|
+
runs-on: ubuntu-latest
|
|
41
|
+
permissions:
|
|
42
|
+
id-token: write # Required for PyPI Trusted Publishing (OIDC)
|
|
43
|
+
contents: read
|
|
44
|
+
|
|
45
|
+
steps:
|
|
46
|
+
- name: Checkout repository
|
|
47
|
+
uses: actions/checkout@v4
|
|
48
|
+
|
|
49
|
+
- name: Set up Python
|
|
50
|
+
uses: actions/setup-python@v5
|
|
51
|
+
with:
|
|
52
|
+
python-version: "3.12"
|
|
53
|
+
|
|
54
|
+
- name: Install build tools
|
|
55
|
+
run: |
|
|
56
|
+
python -m pip install --upgrade pip
|
|
57
|
+
pip install build twine
|
|
58
|
+
|
|
59
|
+
- name: Build package distributions
|
|
60
|
+
run: python -m build
|
|
61
|
+
|
|
62
|
+
- name: Verify package distributions
|
|
63
|
+
run: twine check dist/*
|
|
64
|
+
|
|
65
|
+
- name: Publish package to PyPI
|
|
66
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
67
|
+
with:
|
|
68
|
+
password: ${{ secrets.PYPI_API_TOKEN }}
|
|
69
|
+
skip-existing: true
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# Distribution / packaging
|
|
7
|
+
dist/
|
|
8
|
+
build/
|
|
9
|
+
*.egg-info/
|
|
10
|
+
*.egg
|
|
11
|
+
|
|
12
|
+
# Virtual environments
|
|
13
|
+
.venv/
|
|
14
|
+
venv/
|
|
15
|
+
env/
|
|
16
|
+
ENV/
|
|
17
|
+
|
|
18
|
+
# Testing & caches
|
|
19
|
+
.pytest_cache/
|
|
20
|
+
.coverage
|
|
21
|
+
htmlcov/
|
|
22
|
+
.mypy_cache/
|
|
23
|
+
.ruff_cache/
|
|
24
|
+
|
|
25
|
+
# Local lockfiles and secrets
|
|
26
|
+
.payload_heal_lock.json
|
|
27
|
+
.demo_heal_lock.json
|
|
28
|
+
*.lock
|
|
29
|
+
.env
|
|
30
|
+
.env.*
|
|
31
|
+
|
|
32
|
+
# IDEs
|
|
33
|
+
.vscode/
|
|
34
|
+
.idea/
|
|
35
|
+
*.swp
|
|
36
|
+
*.swo
|
|
37
|
+
|
|
38
|
+
# OS files
|
|
39
|
+
.DS_Store
|
|
40
|
+
Thumbs.db
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Payload Heal Contributors
|
|
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,288 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: payload-heal
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Production-ready self-healing Pydantic models for resilient JSON and GraphQL ingestion
|
|
5
|
+
Author: Payload Heal Contributors
|
|
6
|
+
License: MIT
|
|
7
|
+
License-File: LICENSE
|
|
8
|
+
Keywords: graphql,json,pydantic,resilience,schema-drift,scraping,self-healing
|
|
9
|
+
Classifier: Development Status :: 4 - Beta
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
17
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
18
|
+
Requires-Python: >=3.10
|
|
19
|
+
Requires-Dist: httpx>=0.25.0
|
|
20
|
+
Requires-Dist: pydantic>=2.5.0
|
|
21
|
+
Provides-Extra: dev
|
|
22
|
+
Requires-Dist: pytest-asyncio; extra == 'dev'
|
|
23
|
+
Requires-Dist: pytest>=7.0; extra == 'dev'
|
|
24
|
+
Requires-Dist: ruff; extra == 'dev'
|
|
25
|
+
Description-Content-Type: text/markdown
|
|
26
|
+
|
|
27
|
+
<div align="center">
|
|
28
|
+
|
|
29
|
+
# ๐ฉน payload-heal
|
|
30
|
+
|
|
31
|
+
**Self-Healing Pydantic Models for Web Scrapers, GraphQL Ingestion, and Volatile JSON APIs.**
|
|
32
|
+
|
|
33
|
+
[](https://pypi.org/project/payload-heal/)
|
|
34
|
+
[](https://pypi.org/project/payload-heal/)
|
|
35
|
+
[](https://docs.pydantic.dev/)
|
|
36
|
+
[](https://opensource.org/licenses/MIT)
|
|
37
|
+
[]()
|
|
38
|
+
|
|
39
|
+
*Automatically recovers from renamed keys, camelCase drift, and nested wrapper mutations in 0ms.*
|
|
40
|
+
|
|
41
|
+
</div>
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## โก The 5-Second Pitch
|
|
46
|
+
|
|
47
|
+
Web scrapers and upstream API integrations **break at 2:00 AM** when an engineer renames `price_usd` to `productPrice`, wraps fields inside `data.listing.item`, or migrates to a new GraphQL schema.
|
|
48
|
+
|
|
49
|
+
Calling an LLM on every scraped payload is **unusable**โit adds 800ms of latency, costs thousands of dollars per month, and leaks user PII to external endpoints.
|
|
50
|
+
|
|
51
|
+
**`payload-heal`** provides a drop-in replacement for `pydantic.BaseModel` called **`HealableModel`** with a **3-tier hybrid self-healing engine**:
|
|
52
|
+
- **0ms overhead, $0 cost** on healthy payloads.
|
|
53
|
+
- **<1ms, $0 cost** heuristic auto-healing for 90% of schema drifts (casing, leaf promotion, prefix/suffix changes).
|
|
54
|
+
- **Runs LLMs ONCE per schema drift** on a lightweight, PII-sanitized skeleton, commits the healed path into a local lockfile cache, and **never calls the LLM again**.
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## ๐ง How the 3-Tier Hybrid Engine Works
|
|
59
|
+
|
|
60
|
+
```text
|
|
61
|
+
Incoming JSON / GraphQL Payload
|
|
62
|
+
โ
|
|
63
|
+
โผ
|
|
64
|
+
[ All Required Fields Present? ]
|
|
65
|
+
โโโโ YES โโโโบ [ Fast Path: 0ms Overhead, $0 Cost ] โโโโบ Validated Model
|
|
66
|
+
โ
|
|
67
|
+
โโโโ NO (Schema Drift Detected!)
|
|
68
|
+
โ
|
|
69
|
+
โโโโบ Tier 0: Lockfile Cache (.payload_heal_lock.json)
|
|
70
|
+
โ Lookup previously healed dot paths. (0ms, $0)
|
|
71
|
+
โ *Re-Drift Guard: Auto-invalidates if upstream drifts a second time!
|
|
72
|
+
โ
|
|
73
|
+
โโโโบ Tier 1: Deterministic Heuristic Matcher
|
|
74
|
+
โ Zero-LLM instant recovery in <1ms. ($0)
|
|
75
|
+
โ - camelCase / snake_case / kebab-case normalization
|
|
76
|
+
โ - Nested leaf promotion (e.g., user_id -> data.user.id)
|
|
77
|
+
โ - Token overlap + SequenceMatcher type compatibility
|
|
78
|
+
โ - Ambiguity protection (refuses to guess on tied confidence)
|
|
79
|
+
โ
|
|
80
|
+
โโโโบ Tier 2: AI Skeleton Healer
|
|
81
|
+
Invoked ONLY ONCE when heuristics cannot resolve drift.
|
|
82
|
+
- Generates a 97% compressed, PII-masked JSON skeleton
|
|
83
|
+
- Queries OpenAI / Groq / Ollama / Gemini for path mapping
|
|
84
|
+
- Strict Type-Safety verification prevents cache poisoning
|
|
85
|
+
- Caches result in Tier 0 lockfile and alerts team via Webhook
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## ๐ 30-Second Quickstart
|
|
91
|
+
|
|
92
|
+
### Installation
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
pip install payload-heal
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Drop-In Usage
|
|
99
|
+
|
|
100
|
+
Simply replace `pydantic.BaseModel` with `HealableModel`:
|
|
101
|
+
|
|
102
|
+
```python
|
|
103
|
+
from pydantic import Field
|
|
104
|
+
from payload_heal import HealableModel
|
|
105
|
+
|
|
106
|
+
class Product(HealableModel):
|
|
107
|
+
title: str
|
|
108
|
+
price: float = Field(description="Retail price in USD")
|
|
109
|
+
rating: float
|
|
110
|
+
in_stock: bool
|
|
111
|
+
|
|
112
|
+
# Upstream scraped API drifted: keys renamed and wrapped inside nested objects!
|
|
113
|
+
broken_payload = {
|
|
114
|
+
"status": "ok",
|
|
115
|
+
"data": {
|
|
116
|
+
"itemDetails": {
|
|
117
|
+
"itemTitle": "Sony WH-1000XM5 Wireless Headphones",
|
|
118
|
+
"priceUsd": "399.99", # string coerced to float
|
|
119
|
+
"userRating": 4.8,
|
|
120
|
+
"inStock": "true", # string coerced to bool
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
# Automatically recovers!
|
|
126
|
+
product = Product.model_validate(broken_payload)
|
|
127
|
+
|
|
128
|
+
print(product.title) # "Sony WH-1000XM5 Wireless Headphones"
|
|
129
|
+
print(product.price) # 399.99 (float)
|
|
130
|
+
print(product.rating) # 4.8 (float)
|
|
131
|
+
print(product.in_stock) # True (bool)
|
|
132
|
+
|
|
133
|
+
# Next time this payload is encountered: Tier 0 Lockfile Cache hit in 0ms!
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
## ๐ Supported AI Providers (Tier 2)
|
|
139
|
+
|
|
140
|
+
Configure providers globally or per-model via `HealConfig`:
|
|
141
|
+
|
|
142
|
+
```python
|
|
143
|
+
from typing import ClassVar
|
|
144
|
+
from payload_heal import HealableModel, HealConfig
|
|
145
|
+
|
|
146
|
+
# 1. OpenAI (Default: gpt-4o-mini)
|
|
147
|
+
class OpenAIModel(HealableModel):
|
|
148
|
+
heal_config: ClassVar[HealConfig] = HealConfig(
|
|
149
|
+
llm_provider="openai",
|
|
150
|
+
api_key="sk-..." # or set OPENAI_API_KEY env var
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
# 2. Groq (Ultra-fast Llama-3.3-70B)
|
|
154
|
+
class GroqModel(HealableModel):
|
|
155
|
+
heal_config: ClassVar[HealConfig] = HealConfig(
|
|
156
|
+
llm_provider="groq",
|
|
157
|
+
model="llama-3.3-70b-versatile",
|
|
158
|
+
api_key="gsk_..." # or set GROQ_API_KEY env var
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
# 3. Local Ollama (100% Free & Private on localhost)
|
|
162
|
+
class OllamaModel(HealableModel):
|
|
163
|
+
heal_config: ClassVar[HealConfig] = HealConfig(
|
|
164
|
+
llm_provider="ollama",
|
|
165
|
+
model="llama3",
|
|
166
|
+
api_base="http://localhost:11434/v1"
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
# 4. Google Gemini
|
|
170
|
+
class GeminiModel(HealableModel):
|
|
171
|
+
heal_config: ClassVar[HealConfig] = HealConfig(
|
|
172
|
+
llm_provider="gemini",
|
|
173
|
+
api_key="..." # or set GEMINI_API_KEY env var
|
|
174
|
+
)
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
---
|
|
178
|
+
|
|
179
|
+
## ๐ ๏ธ Standalone Decorator (`@heal_json`)
|
|
180
|
+
|
|
181
|
+
Wrap existing third-party models or function handlers without modifying class definitions:
|
|
182
|
+
|
|
183
|
+
```python
|
|
184
|
+
from pydantic import BaseModel
|
|
185
|
+
from payload_heal import heal_json
|
|
186
|
+
|
|
187
|
+
class ThirdPartySchema(BaseModel):
|
|
188
|
+
user_id: int
|
|
189
|
+
email: str
|
|
190
|
+
|
|
191
|
+
@heal_json(ThirdPartySchema)
|
|
192
|
+
def ingest_webhook(payload: dict):
|
|
193
|
+
# payload is healed before function execution
|
|
194
|
+
user = ThirdPartySchema.model_validate(payload)
|
|
195
|
+
print(f"Processed user #{user.user_id}: {user.email}")
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
---
|
|
199
|
+
|
|
200
|
+
## ๐ก๏ธ Privacy-First PII Masking
|
|
201
|
+
|
|
202
|
+
Before any skeleton is sent to an external LLM endpoint, `payload-heal` automatically redacts sensitive data from preview samples:
|
|
203
|
+
- **Email Addresses**: `user@domain.com` -> `[MASKED_EMAIL]`
|
|
204
|
+
- **Bearer & JWT Tokens**: `Bearer eyJhbGci...` -> `Bearer [MASKED_TOKEN]`
|
|
205
|
+
- **API Keys**: `sk-proj-1234...` -> `[MASKED_TOKEN]`
|
|
206
|
+
- **Credit Cards**: `4111-2222-3333-4444` (and Luhn-validated sequences) -> `[MASKED_CREDIT_CARD]`
|
|
207
|
+
|
|
208
|
+
---
|
|
209
|
+
|
|
210
|
+
## ๐ Slack / Discord Webhook Drift Alerts
|
|
211
|
+
|
|
212
|
+
Get notified in Slack or Discord the moment an upstream API drifts:
|
|
213
|
+
|
|
214
|
+
```python
|
|
215
|
+
class MonitoredModel(HealableModel):
|
|
216
|
+
heal_config: ClassVar[HealConfig] = HealConfig(
|
|
217
|
+
webhook_url="https://hooks.slack.com/services/T00/B00/X00" # or Discord webhook
|
|
218
|
+
)
|
|
219
|
+
price: float
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
When schema drift is resolved, `payload-heal` fires a non-blocking notification:
|
|
223
|
+
```text
|
|
224
|
+
โ ๏ธ Payload Schema Drift Healed
|
|
225
|
+
Model: MonitoredModel
|
|
226
|
+
Healed Fields (1):
|
|
227
|
+
โข price โ data.pricing.priceUsd (healed by heuristic)
|
|
228
|
+
Lockfile updated automatically. No immediate action required.
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
---
|
|
232
|
+
|
|
233
|
+
## ๐ป Developer CLI
|
|
234
|
+
|
|
235
|
+
Inspect skeletons and manage lockfiles from your terminal:
|
|
236
|
+
|
|
237
|
+
```bash
|
|
238
|
+
# View all healed models and field mappings
|
|
239
|
+
payload-heal status
|
|
240
|
+
|
|
241
|
+
# Inspect a raw JSON file and view skeleton compression ratio
|
|
242
|
+
payload-heal inspect scraper_dump.json
|
|
243
|
+
|
|
244
|
+
# Reset cached mappings for a specific model (or all models)
|
|
245
|
+
payload-heal reset ProductModel
|
|
246
|
+
payload-heal reset
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
---
|
|
250
|
+
|
|
251
|
+
## ๐ Try the Live Demo
|
|
252
|
+
|
|
253
|
+
Run the self-contained scraper drift simulation:
|
|
254
|
+
|
|
255
|
+
```bash
|
|
256
|
+
python examples/demo_scraper_drift.py
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
Output:
|
|
260
|
+
```text
|
|
261
|
+
=====================================================================================
|
|
262
|
+
PAYLOAD-HEAL LIVE DEMO: Resilient Web Scraper Ingestion
|
|
263
|
+
=====================================================================================
|
|
264
|
+
Iteration API State Tier Used Latency Status
|
|
265
|
+
-------------------------------------------------------------------------------------
|
|
266
|
+
Run 1 v1 (Normal Schema) Fast Path (0ms, $0) 0.074 ms [OK] Ingested
|
|
267
|
+
Run 2 v2 (camelCase + Nesting) Tier-1 Heuristic ($0) 24.551 ms [OK] Healed
|
|
268
|
+
Run 3 v3 (Complete Rewrite) Tier-2 AI Healer 46.463 ms [OK] Healed & Cached
|
|
269
|
+
Run 4 v3 Repeat Payload Tier-0 Lockfile (0ms) 2.693 ms [OK] 0ms Cache Hit
|
|
270
|
+
-------------------------------------------------------------------------------------
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
---
|
|
274
|
+
|
|
275
|
+
## ๐งช Test Suite
|
|
276
|
+
|
|
277
|
+
Run unit and integration tests across all modules:
|
|
278
|
+
|
|
279
|
+
```bash
|
|
280
|
+
pytest -v
|
|
281
|
+
```
|
|
282
|
+
All **54 tests** pass in ~4 seconds.
|
|
283
|
+
|
|
284
|
+
---
|
|
285
|
+
|
|
286
|
+
## ๐ License
|
|
287
|
+
|
|
288
|
+
MIT License. See [LICENSE](LICENSE) for details. Built for resilient engineering teams.
|