Skip to content

Commit 072ddd6

Browse files
committed
chore: seal sentinel doctrine (v1.0.0)
1 parent 5acdd44 commit 072ddd6

4 files changed

Lines changed: 399 additions & 0 deletions

File tree

.github/workflows/ci.yml

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
name: keon-sdk CI
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
pull_request:
8+
9+
jobs:
10+
sentinels:
11+
name: Architecture Sentinels
12+
runs-on: ubuntu-latest
13+
14+
steps:
15+
- name: Checkout code
16+
uses: actions/checkout@v4
17+
18+
- name: Set up Python
19+
uses: actions/setup-python@v5
20+
with:
21+
python-version: "3.11"
22+
cache: "pip"
23+
24+
- name: Install dependencies
25+
run: |
26+
python -m pip install --upgrade pip
27+
pip install -e ".[dev]"
28+
29+
- name: Verify sentinel count (meta-sentinel)
30+
run: |
31+
COUNT=$(python -m pytest --co -q -m sentinel 2>&1 | grep -c "::" || true)
32+
echo "Sentinel count: $COUNT"
33+
if [ "$COUNT" -lt 9 ]; then
34+
echo "SENTINEL SUITE TOO SMALL: found $COUNT, expected >= 9"
35+
echo "Sentinels may have been deleted. No merge until count is restored."
36+
exit 1
37+
fi
38+
39+
- name: Run architecture sentinels
40+
run: |
41+
python -m pytest tests/test_keon_sentinels.py -m sentinel -v --no-header --tb=short
42+
43+
test:
44+
name: Full Test Suite
45+
needs: [sentinels]
46+
runs-on: ubuntu-latest
47+
strategy:
48+
matrix:
49+
python-version: ["3.11", "3.12"]
50+
51+
steps:
52+
- name: Checkout code
53+
uses: actions/checkout@v4
54+
55+
- name: Set up Python ${{ matrix.python-version }}
56+
uses: actions/setup-python@v5
57+
with:
58+
python-version: ${{ matrix.python-version }}
59+
cache: "pip"
60+
61+
- name: Install dependencies
62+
run: |
63+
python -m pip install --upgrade pip
64+
pip install -e ".[dev]"
65+
66+
- name: Run tests
67+
run: |
68+
python -m pytest --cov=keon_sdk --cov-report=xml --cov-report=term
69+
70+
- name: Upload coverage
71+
uses: codecov/codecov-action@v4
72+
with:
73+
file: ./coverage.xml
74+
flags: keon-sdk
75+
name: keon-sdk-${{ matrix.python-version }}
76+
77+
lint:
78+
name: Lint
79+
runs-on: ubuntu-latest
80+
81+
steps:
82+
- name: Checkout code
83+
uses: actions/checkout@v4
84+
85+
- name: Set up Python
86+
uses: actions/setup-python@v5
87+
with:
88+
python-version: "3.11"
89+
cache: "pip"
90+
91+
- name: Install dependencies
92+
run: |
93+
python -m pip install --upgrade pip
94+
pip install -e ".[dev]"
95+
96+
- name: Run Black
97+
run: black --check keon_sdk/ tests/
98+
99+
- name: Run Ruff
100+
run: ruff check keon_sdk/ tests/
101+
102+
- name: Run MyPy
103+
run: mypy keon_sdk/
104+

SENTINELS.md

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
# keon-sdk-python — Architecture Sentinels
2+
3+
**Status:** SEALED
4+
**Scope:** Architecture + Contract Guardrails
5+
**Rule:** No merge to main with sentinel failures.
6+
**Layer:** Policy SDK — enforces that policy authority is sovereign and cannot be weakened.
7+
8+
---
9+
10+
## What these sentinels protect
11+
12+
Sentinels are non-negotiable guardrails that prevent architectural drift and authority weakening.
13+
They are designed to fail closed.
14+
15+
## Required Suites
16+
17+
- `pytest -q` must include the sentinel file.
18+
- CI must block merges if sentinel suites are skipped or fail.
19+
- The `sentinels` CI job gates `test`, which gates `lint`.
20+
21+
## Failure Philosophy
22+
23+
- **Fail-closed:** If authority cannot be verified, the system must refuse to proceed.
24+
- **No silent downgrade:** Contract drift must be explicit and reviewed.
25+
- **No bypass paths:** Forbidden shortcuts are treated as defects, not optimizations.
26+
27+
## Sentinel Inventory
28+
29+
> Update this list intentionally. Removing or weakening sentinels requires doctrine review.
30+
31+
**Guarantee:** DecideRequest + DecisionReceipt strict, timeout → `NetworkError`, policy authority cannot silently weaken.
32+
33+
| File | ID | Invariant |
34+
|------|----|-----------|
35+
| `test_keon_sentinels.py` | KEON-SDK-1a | `DecideRequest` without `correlationId` fails at construction |
36+
| `test_keon_sentinels.py` | KEON-SDK-1a | Malformed `correlationId` (non-uuidv7) rejected at construction |
37+
| `test_keon_sentinels.py` | KEON-SDK-1a | `tenantId` and `actorId` both mandatory — absent cases fail |
38+
| `test_keon_sentinels.py` | KEON-SDK-1b | `DecisionReceipt` without `receiptId` fails at construction |
39+
| `test_keon_sentinels.py` | KEON-SDK-1b | `receiptId` not matching `^dr-<uuidv7>` rejected |
40+
| `test_keon_sentinels.py` | KEON-SDK-1b | `DecisionReceipt` without `decision` field fails |
41+
| `test_keon_sentinels.py` | KEON-SDK-1c | Gateway timeout → `NetworkError`; never silently allows on failure |
42+
| `test_keon_sentinels.py` | DRIFT-1 | `DecideRequest` required-field set matches approved hash (no silent additions/removals) |
43+
| `test_keon_sentinels.py` | DRIFT-2 | `DecisionReceipt` required-field set matches approved hash (no silent additions/removals) |
44+
45+
---
46+
47+
## How to Run
48+
49+
```bash
50+
cd keon-sdk-python
51+
pytest -q
52+
```
53+
54+
---
55+
56+
## Drift Tripwires
57+
58+
`DRIFT-1` and `DRIFT-2` hash the set of required fields in `DecideRequest` and `DecisionReceipt` at test time using `model_fields`. If any required field is added or removed without updating the stored hash, CI fails.
59+
60+
To update after an approved schema change:
61+
1. Make the intentional change to the Pydantic model.
62+
2. Compute the new hash:
63+
```python
64+
python -c "
65+
import hashlib, json
66+
from keon_sdk.contracts import DecideRequest
67+
fields = sorted(n for n, i in DecideRequest.model_fields.items() if i.is_required())
68+
print(hashlib.sha256(json.dumps(fields, sort_keys=True).encode()).hexdigest()[:16])
69+
"
70+
```
71+
3. Update `_DECIDE_FIELDS_HASH` or `_RECEIPT_FIELDS_HASH` in `test_keon_sentinels.py`.
72+
4. Commit: `sentinel(drift): approve <what changed><reason>`.
73+
74+
---
75+
76+
## Seal Record
77+
78+
- **Tag:** `keon-sdk-sentinels-v1.0.0`
79+
- **Commit:** `6da04940a6e109db6c57fd12583d5ac9cc67ede2`
80+
- **Date:** 2026-02-22
81+

pyproject.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,9 @@ python_classes = "Test*"
9191
python_functions = "test_*"
9292
addopts = "-v --cov=keon_sdk --cov-report=term-missing --cov-report=html"
9393
asyncio_mode = "auto"
94+
markers = [
95+
"sentinel: architecture guard tests — enforce policy authority contract",
96+
]
9497

9598
[tool.coverage.run]
9699
source = ["keon_sdk"]

0 commit comments

Comments
 (0)