docs: add AGENTS.python/go/typescript.md and pre-push check rules
Some checks failed
CI / go-lint (push) Has been cancelled
CI / python-lint (push) Has been cancelled
CI / nodejs-lint (push) Has been cancelled
CI / test-go-consent (push) Has been cancelled
CI / test-python-voice (push) Has been cancelled
CI / test-bqas (push) Has been cancelled
Some checks failed
CI / go-lint (push) Has been cancelled
CI / python-lint (push) Has been cancelled
CI / nodejs-lint (push) Has been cancelled
CI / test-go-consent (push) Has been cancelled
CI / test-python-voice (push) Has been cancelled
CI / test-bqas (push) Has been cancelled
Mandatory pre-push gates for all three language stacks with exact commands, common pitfalls, and architecture rules. CLAUDE.md updated with quick-reference section linking to the new files. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
157
.claude/AGENTS.python.md
Normal file
157
.claude/AGENTS.python.md
Normal file
@@ -0,0 +1,157 @@
|
||||
# AGENTS.python.md — Python Agent Rules
|
||||
|
||||
Applies to: `backend-compliance/`, `ai-compliance-sdk/` (Python path), `compliance-tts-service/`, `document-crawler/`, `dsms-gateway/` (Python services)
|
||||
|
||||
---
|
||||
|
||||
## NON-NEGOTIABLE: Pre-Push Checklist
|
||||
|
||||
**BEFORE every `git push`, run ALL of the following from the service directory. A single failure blocks the push.**
|
||||
|
||||
```bash
|
||||
# 1. Fast lint (Ruff — catches syntax errors, unused imports, style violations)
|
||||
ruff check .
|
||||
|
||||
# 2. Auto-fix safe issues, then re-check
|
||||
ruff check --fix . && ruff check .
|
||||
|
||||
# 3. Type checking (mypy strict on new modules, standard on legacy)
|
||||
mypy . --ignore-missing-imports --no-error-summary
|
||||
|
||||
# 4. Unit tests only (fast, no external deps)
|
||||
pytest tests/unit/ -x -q --no-header
|
||||
|
||||
# 5. Verify the service starts (catches import errors, missing env vars with defaults)
|
||||
python -c "import app" 2>/dev/null || python -c "import main" 2>/dev/null || true
|
||||
```
|
||||
|
||||
**One-liner pre-push gate (run from service root):**
|
||||
```bash
|
||||
ruff check . && mypy . --ignore-missing-imports --no-error-summary && pytest tests/ -x -q --no-header
|
||||
```
|
||||
|
||||
### Why each check matters
|
||||
|
||||
| Check | Catches | Time |
|
||||
|-------|---------|------|
|
||||
| `ruff check` | Syntax errors, unused imports, undefined names | <2s |
|
||||
| `mypy` | Type mismatches, wrong argument types | 5-15s |
|
||||
| `pytest -x` | Logic errors, regressions | 10-60s |
|
||||
| import check | Missing packages, circular imports | <1s |
|
||||
|
||||
---
|
||||
|
||||
## Code Style (Ruff)
|
||||
|
||||
Config lives in `pyproject.toml`. Do **not** add per-file `# noqa` suppressions without a comment explaining why.
|
||||
|
||||
```toml
|
||||
[tool.ruff]
|
||||
line-length = 100
|
||||
target-version = "py311"
|
||||
|
||||
[tool.ruff.lint]
|
||||
select = ["E", "F", "W", "I", "N", "UP", "B", "C4", "SIM", "TCH"]
|
||||
ignore = ["E501"] # line length handled by formatter
|
||||
|
||||
[tool.ruff.lint.per-file-ignores]
|
||||
"tests/*" = ["S101"] # assert is fine in tests
|
||||
```
|
||||
|
||||
**Blocked patterns:**
|
||||
- `from module import *` — always name imports explicitly
|
||||
- Bare `except:` — use `except Exception as e:` at minimum
|
||||
- `print()` in production code — use `logger`
|
||||
- Mutable default arguments: `def f(x=[])` → `def f(x=None)`
|
||||
|
||||
---
|
||||
|
||||
## Type Annotations
|
||||
|
||||
All new functions **must** have complete type annotations. Use `from __future__ import annotations` for forward references.
|
||||
|
||||
```python
|
||||
# Required
|
||||
async def get_tenant(tenant_id: str, db: AsyncSession) -> TenantModel | None:
|
||||
...
|
||||
|
||||
# Required for complex types
|
||||
from typing import Sequence
|
||||
def list_risks(filters: dict[str, str]) -> Sequence[RiskModel]:
|
||||
...
|
||||
```
|
||||
|
||||
**Mypy rules:**
|
||||
- `--disallow-untyped-defs` on new files
|
||||
- `--strict` on new modules (not legacy)
|
||||
- Never use `type: ignore` without a comment
|
||||
|
||||
---
|
||||
|
||||
## FastAPI-Specific Rules
|
||||
|
||||
```python
|
||||
# Handlers stay thin — delegate to service layer
|
||||
@router.get("/risks/{risk_id}", response_model=RiskResponse)
|
||||
async def get_risk(risk_id: UUID, service: RiskService = Depends(get_risk_service)):
|
||||
return await service.get(risk_id) # ≤5 lines per handler
|
||||
|
||||
# Always use response_model — never return raw dicts from endpoints
|
||||
# Always validate input with Pydantic — no manual dict parsing
|
||||
# Use HTTPException with specific status codes, never bare 500
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Testing Requirements
|
||||
|
||||
```
|
||||
tests/
|
||||
├── unit/ # Pure logic tests, no DB/HTTP (run on every push)
|
||||
├── integration/ # Requires running services (run in CI only)
|
||||
└── contracts/ # OpenAPI snapshot tests (run on API changes)
|
||||
```
|
||||
|
||||
**Unit test requirements:**
|
||||
- Every new function → at least one happy-path test
|
||||
- Every bug fix → regression test that would have caught it
|
||||
- Mock all I/O: DB calls, HTTP calls, filesystem reads
|
||||
|
||||
```bash
|
||||
# Run unit tests only (fast, for pre-push)
|
||||
pytest tests/unit/ -x -q
|
||||
|
||||
# Run with coverage (for CI)
|
||||
pytest tests/ --cov=. --cov-report=term-missing --cov-fail-under=70
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Dependency Management
|
||||
|
||||
```bash
|
||||
# Check new package license before adding
|
||||
pip show <package> | grep -E "License|Home-page"
|
||||
|
||||
# After adding to requirements.txt — verify no GPL/AGPL
|
||||
pip-licenses --fail-on="GPL;AGPL" 2>/dev/null || echo "Check licenses manually"
|
||||
```
|
||||
|
||||
**Never add:**
|
||||
- GPL/AGPL licensed packages
|
||||
- Packages with known CVEs (`pip audit`)
|
||||
- Packages that only exist for dev (`pytest`, `ruff`) to production requirements
|
||||
|
||||
---
|
||||
|
||||
## Common Pitfalls That Break CI
|
||||
|
||||
| Pitfall | Prevention |
|
||||
|---------|------------|
|
||||
| `const x = ...` inside dict literal (wrong language!) | Run ruff before push |
|
||||
| Pydantic v1 syntax in v2 project | Use `model_config`, not `class Config` |
|
||||
| Sync function called inside async without `run_in_executor` | mypy + async linter |
|
||||
| Missing `await` on coroutine | mypy catches this |
|
||||
| `datetime.utcnow()` (deprecated) | Use `datetime.now(timezone.utc)` |
|
||||
| Bare `except:` swallowing errors silently | ruff B001/E722 catches this |
|
||||
| Unused imports left in committed code | ruff F401 catches this |
|
||||
Reference in New Issue
Block a user