tribunal-kit 4.3.0 → 4.4.0

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 (120) hide show
  1. package/.agent/history/architecture-explorer.html +352 -0
  2. package/.agent/history/architecture-graph.yaml +109 -0
  3. package/.agent/history/graph-cache.json +215 -0
  4. package/.agent/history/snapshots/migrate_refs.js.json +11 -0
  5. package/.agent/history/snapshots/scripts__changelog.js.json +12 -0
  6. package/.agent/history/snapshots/scripts__sync-version.js.json +11 -0
  7. package/.agent/history/snapshots/scripts__validate-payload.js.json +11 -0
  8. package/.agent/history/snapshots/test__integration__bridges.test.js.json +13 -0
  9. package/.agent/history/snapshots/test__integration__init.test.js.json +13 -0
  10. package/.agent/history/snapshots/test__integration__routing.test.js.json +11 -0
  11. package/.agent/history/snapshots/test__integration__swarm_dispatcher.test.js.json +13 -0
  12. package/.agent/history/snapshots/test__integration__wave2.test.js.json +13 -0
  13. package/.agent/history/snapshots/test__unit__args.test.js.json +10 -0
  14. package/.agent/history/snapshots/test__unit__case_law_manager.test.js.json +10 -0
  15. package/.agent/history/snapshots/test__unit__copyDir.test.js.json +13 -0
  16. package/.agent/history/snapshots/test__unit__graph_tools.test.js.json +11 -0
  17. package/.agent/history/snapshots/test__unit__selfInstall.test.js.json +13 -0
  18. package/.agent/history/snapshots/test__unit__semver.test.js.json +10 -0
  19. package/.agent/history/snapshots/test__unit__swarm_dispatcher.test.js.json +11 -0
  20. package/.agent/scripts/case_law_manager.js +684 -684
  21. package/.agent/scripts/dependency_analyzer.js +1 -1
  22. package/.agent/scripts/graph_builder.js +311 -0
  23. package/.agent/scripts/graph_visualizer.js +384 -0
  24. package/.agent/scripts/graph_zoom.js +154 -0
  25. package/.agent/scripts/mutation_runner.js +280 -0
  26. package/.agent/skills/agent-organizer/SKILL.md +9 -1
  27. package/.agent/skills/agentic-patterns/SKILL.md +9 -1
  28. package/.agent/skills/ai-prompt-injection-defense/SKILL.md +9 -1
  29. package/.agent/skills/api-patterns/SKILL.md +206 -198
  30. package/.agent/skills/api-security-auditor/SKILL.md +9 -1
  31. package/.agent/skills/app-builder/SKILL.md +9 -1
  32. package/.agent/skills/app-builder/templates/SKILL.md +77 -69
  33. package/.agent/skills/appflow-wireframe/SKILL.md +9 -1
  34. package/.agent/skills/architecture/SKILL.md +9 -1
  35. package/.agent/skills/authentication-best-practices/SKILL.md +9 -1
  36. package/.agent/skills/bash-linux/SKILL.md +9 -1
  37. package/.agent/skills/behavioral-modes/SKILL.md +9 -1
  38. package/.agent/skills/brainstorming/SKILL.md +9 -1
  39. package/.agent/skills/building-native-ui/SKILL.md +9 -1
  40. package/.agent/skills/clean-code/SKILL.md +9 -1
  41. package/.agent/skills/code-review-checklist/SKILL.md +9 -1
  42. package/.agent/skills/config-validator/SKILL.md +9 -1
  43. package/.agent/skills/csharp-developer/SKILL.md +9 -1
  44. package/.agent/skills/data-validation-schemas/SKILL.md +287 -279
  45. package/.agent/skills/database-design/SKILL.md +199 -191
  46. package/.agent/skills/deployment-procedures/SKILL.md +9 -1
  47. package/.agent/skills/devops-engineer/SKILL.md +9 -1
  48. package/.agent/skills/devops-incident-responder/SKILL.md +9 -1
  49. package/.agent/skills/documentation-templates/SKILL.md +9 -1
  50. package/.agent/skills/edge-computing/SKILL.md +9 -1
  51. package/.agent/skills/error-resilience/SKILL.md +387 -379
  52. package/.agent/skills/extract-design-system/SKILL.md +9 -1
  53. package/.agent/skills/framer-motion-expert/SKILL.md +203 -195
  54. package/.agent/skills/frontend-design/SKILL.md +160 -152
  55. package/.agent/skills/game-design-expert/SKILL.md +9 -1
  56. package/.agent/skills/game-engineering-expert/SKILL.md +9 -1
  57. package/.agent/skills/geo-fundamentals/SKILL.md +9 -1
  58. package/.agent/skills/github-operations/SKILL.md +9 -1
  59. package/.agent/skills/gsap-core/SKILL.md +54 -46
  60. package/.agent/skills/gsap-frameworks/SKILL.md +54 -46
  61. package/.agent/skills/gsap-performance/SKILL.md +54 -46
  62. package/.agent/skills/gsap-plugins/SKILL.md +54 -46
  63. package/.agent/skills/gsap-react/SKILL.md +54 -46
  64. package/.agent/skills/gsap-scrolltrigger/SKILL.md +54 -46
  65. package/.agent/skills/gsap-timeline/SKILL.md +54 -46
  66. package/.agent/skills/gsap-utils/SKILL.md +54 -46
  67. package/.agent/skills/i18n-localization/SKILL.md +9 -1
  68. package/.agent/skills/intelligent-routing/SKILL.md +38 -30
  69. package/.agent/skills/knowledge-graph/SKILL.md +52 -0
  70. package/.agent/skills/lint-and-validate/SKILL.md +9 -1
  71. package/.agent/skills/llm-engineering/SKILL.md +9 -1
  72. package/.agent/skills/local-first/SKILL.md +9 -1
  73. package/.agent/skills/mcp-builder/SKILL.md +9 -1
  74. package/.agent/skills/mobile-design/SKILL.md +222 -214
  75. package/.agent/skills/monorepo-management/SKILL.md +293 -285
  76. package/.agent/skills/motion-engineering/SKILL.md +193 -185
  77. package/.agent/skills/nextjs-react-expert/SKILL.md +193 -185
  78. package/.agent/skills/nodejs-best-practices/SKILL.md +9 -1
  79. package/.agent/skills/observability/SKILL.md +9 -1
  80. package/.agent/skills/parallel-agents/SKILL.md +9 -1
  81. package/.agent/skills/performance-profiling/SKILL.md +9 -1
  82. package/.agent/skills/plan-writing/SKILL.md +9 -1
  83. package/.agent/skills/platform-engineer/SKILL.md +9 -1
  84. package/.agent/skills/playwright-best-practices/SKILL.md +9 -1
  85. package/.agent/skills/powershell-windows/SKILL.md +9 -1
  86. package/.agent/skills/project-idioms/SKILL.md +9 -1
  87. package/.agent/skills/python-patterns/SKILL.md +9 -1
  88. package/.agent/skills/python-pro/SKILL.md +282 -274
  89. package/.agent/skills/react-specialist/SKILL.md +236 -228
  90. package/.agent/skills/readme-builder/SKILL.md +9 -1
  91. package/.agent/skills/realtime-patterns/SKILL.md +9 -1
  92. package/.agent/skills/red-team-tactics/SKILL.md +9 -1
  93. package/.agent/skills/rust-pro/SKILL.md +9 -1
  94. package/.agent/skills/seo-fundamentals/SKILL.md +9 -1
  95. package/.agent/skills/server-management/SKILL.md +9 -1
  96. package/.agent/skills/shadcn-ui-expert/SKILL.md +9 -1
  97. package/.agent/skills/skill-creator/SKILL.md +9 -1
  98. package/.agent/skills/sql-pro/SKILL.md +9 -1
  99. package/.agent/skills/supabase-postgres-best-practices/SKILL.md +9 -1
  100. package/.agent/skills/swiftui-expert/SKILL.md +9 -1
  101. package/.agent/skills/systematic-debugging/SKILL.md +9 -1
  102. package/.agent/skills/tailwind-patterns/SKILL.md +9 -1
  103. package/.agent/skills/tdd-workflow/SKILL.md +9 -1
  104. package/.agent/skills/test-result-analyzer/SKILL.md +9 -1
  105. package/.agent/skills/testing-patterns/SKILL.md +28 -3
  106. package/.agent/skills/trend-researcher/SKILL.md +9 -1
  107. package/.agent/skills/typescript-advanced/SKILL.md +294 -286
  108. package/.agent/skills/ui-ux-pro-max/SKILL.md +561 -116
  109. package/.agent/skills/ui-ux-researcher/SKILL.md +9 -1
  110. package/.agent/skills/vue-expert/SKILL.md +234 -226
  111. package/.agent/skills/vulnerability-scanner/SKILL.md +9 -1
  112. package/.agent/skills/web-accessibility-auditor/SKILL.md +9 -1
  113. package/.agent/skills/web-design-guidelines/SKILL.md +9 -1
  114. package/.agent/skills/webapp-testing/SKILL.md +9 -1
  115. package/.agent/skills/whimsy-injector/SKILL.md +9 -1
  116. package/.agent/skills/workflow-optimizer/SKILL.md +9 -1
  117. package/README.md +242 -242
  118. package/bin/tribunal-kit.js +157 -21
  119. package/package.json +81 -80
  120. package/scripts/validate-payload.js +73 -0
@@ -1,276 +1,276 @@
1
- ---
2
- name: python-pro
3
- description: Python 3.12+ specialist. FastAPI, Pydantic v2, asyncio, modern types, pytest. Use when building Python APIs, data pipelines, automation, or any Python code.
4
- allowed-tools: Read, Write, Edit, Glob, Grep
5
- version: 3.1.0
6
- last-updated: 2026-04-06
7
- ---
8
-
9
- # Python 3.12+ — Dense Reference
10
-
11
- ## Hallucination Traps (Read First)
12
- - ❌ `from typing import List, Dict, Optional, Union` → ✅ `list[str]`, `dict[k,v]`, `X | None`, `X | Y` (Python 3.10+)
13
- - ❌ `user.dict()` / `user.json()` / `UserCreate.parse_obj()` → ✅ Pydantic v2: `model_dump()`, `model_dump_json()`, `model_validate()`
14
- - ❌ Pydantic `class Config: orm_mode = True` → ✅ `model_config = {"from_attributes": True}`
15
- - ❌ `@validator` / `@root_validator` → ✅ `@field_validator` / `@model_validator`
16
- - ❌ `@app.on_event("startup")` → ✅ `lifespan` context manager (deprecated)
17
- - ❌ `import requests` in async code → ✅ `httpx.AsyncClient()` (requests BLOCKS the event loop)
18
- - ❌ `asyncio.run()` inside running loop → ✅ `await` directly or use `loop.create_task()`
19
- - ❌ `except Exception as e: pass` → ✅ always log or re-raise
20
-
21
- ---
22
-
23
- ## Type System (3.12+)
24
-
25
- ```python
26
- # Built-in generics (3.9+) — no typing imports needed for basic types
27
- def process(items: list[str]) -> dict[str, int]: ...
28
- def find(user_id: int) -> User | None: ... # 3.10+ union
29
- def parse(raw: str) -> int | float | None: ...
30
-
31
- # Generic syntax (3.12+)
32
- def first[T](items: list[T]) -> T | None:
33
- return items[0] if items else None
34
- type Point = tuple[float, float] # 3.12+ type alias
35
-
36
- # Protocol (structural typing — duck typing with types)
37
- from typing import Protocol, runtime_checkable
38
- @runtime_checkable
39
- class Renderable(Protocol):
40
- def render(self) -> str: ...
41
-
42
- # TypedDict — typed dict with optional keys
43
- from typing import TypedDict, NotRequired
44
- class UserPayload(TypedDict):
45
- name: str; email: str
46
- age: NotRequired[int] # optional key
47
-
48
- # ParamSpec — preserve signatures in decorators
49
- from typing import TypeVar, ParamSpec
50
- from collections.abc import Callable
51
- T = TypeVar("T"); P = ParamSpec("P")
52
- def with_logging(func: Callable[P, T]) -> Callable[P, T]:
53
- def wrapper(*args: P.args, **kwargs: P.kwargs) -> T:
54
- result = func(*args, **kwargs)
55
- return result
56
- return wrapper
57
- ```
58
-
59
- ---
60
-
61
- ## Pydantic v2
62
-
63
- ```python
64
- from pydantic import BaseModel, Field, field_validator, model_validator
65
- from enum import Enum
66
-
67
- class Role(str, Enum):
68
- ADMIN = "admin"; USER = "user"
69
-
70
- class UserCreate(BaseModel):
71
- name: str = Field(..., min_length=2, max_length=100)
72
- email: str = Field(..., pattern=r"^[\w.-]+@[\w.-]+\.\w+$")
73
- age: int = Field(..., ge=13, le=120)
74
- role: Role = Role.USER
75
- tags: list[str] = Field(default_factory=list)
76
-
77
- @field_validator("name")
78
- @classmethod
79
- def name_titlecase(cls, v: str) -> str:
80
- if not v[0].isupper(): raise ValueError("Name must start with uppercase")
81
- return v.strip()
82
-
83
- @model_validator(mode="after")
84
- def check_admin_age(self) -> "UserCreate":
85
- if self.role == Role.ADMIN and self.age < 18:
86
- raise ValueError("Admins must be 18+")
87
- return self
88
-
89
- class UserResponse(BaseModel):
90
- id: int; name: str; email: str
91
- model_config = {"from_attributes": True} # ORM mode (was orm_mode=True in v1)
92
-
93
- # Serialization
94
- user.model_dump() # ✅ (was .dict())
95
- user.model_dump_json() # ✅ (was .json())
96
- user.model_dump(exclude={"password"}, mode="json")
97
- UserCreate.model_validate({"name": "Alice", "email": "a@b.com", "age": 30}) # ✅ (was parse_obj)
98
- UserCreate.model_validate_json('{"name": "Bob", ...}')
99
- ```
100
-
101
- ---
102
-
103
- ## FastAPI
104
-
105
- ```python
106
- from fastapi import FastAPI, HTTPException, Depends, Query, Path, status
107
- from contextlib import asynccontextmanager
108
-
109
- @asynccontextmanager
110
- async def lifespan(app: FastAPI):
111
- await init_db(); await redis.connect() # startup
112
- yield
113
- await redis.close() # shutdown
114
-
115
- app = FastAPI(title="My API", version="1.0.0", lifespan=lifespan)
116
-
117
- # CORS — never "*" in production
118
- from fastapi.middleware.cors import CORSMiddleware
119
- app.add_middleware(CORSMiddleware,
120
- allow_origins=["https://myapp.com"], # ❌ NEVER ["*"]
121
- allow_credentials=True, allow_methods=["GET","POST","PUT","DELETE"], allow_headers=["*"])
122
-
123
- # Routes
124
- @app.get("/users", response_model=list[UserResponse])
125
- async def list_users(skip: int = Query(0, ge=0), limit: int = Query(20, le=100)) -> list[UserResponse]:
126
- return await db.execute(select(User).offset(skip).limit(limit))
127
-
128
- @app.post("/users", response_model=UserResponse, status_code=status.HTTP_201_CREATED)
129
- async def create_user(payload: UserCreate) -> UserResponse:
130
- user = User(**payload.model_dump())
131
- db.add(user); await db.commit(); await db.refresh(user)
132
- return user
133
-
134
- # Dependency Injection
135
- async def get_db() -> AsyncGenerator[AsyncSession, None]:
136
- async with async_session() as session:
137
- try: yield session
138
- finally: await session.close()
139
-
140
- async def get_current_user(token: str = Depends(oauth2_scheme), db: AsyncSession = Depends(get_db)) -> User:
141
- payload = decode_jwt(token)
142
- user = await db.get(User, payload["sub"])
143
- if not user: raise HTTPException(status_code=401, detail="Invalid credentials")
144
- return user
145
-
146
- def require_role(role: Role):
147
- async def checker(user: User = Depends(get_current_user)) -> User:
148
- if user.role != role: raise HTTPException(status_code=403, detail="Forbidden")
149
- return user
150
- return checker
151
-
152
- # Background Tasks
153
- from fastapi import BackgroundTasks
154
- @app.post("/orders")
155
- async def create_order(order: OrderCreate, bg: BackgroundTasks) -> OrderResponse:
156
- result = await save_order(order)
157
- bg.add_task(send_email, result.email)
158
- return result
159
-
160
- # Exception handlers
161
- from fastapi.responses import JSONResponse
162
- @app.exception_handler(AppError)
163
- async def app_error(request: Request, exc: AppError) -> JSONResponse:
164
- return JSONResponse(status_code=exc.status_code, content={"error": exc.message})
165
- ```
166
-
167
- ---
168
-
169
- ## Async Patterns
170
-
171
- ```python
172
- import asyncio, httpx
173
-
174
- # Parallel calls — await all simultaneously
175
- async def fetch_all() -> tuple:
176
- async with httpx.AsyncClient() as client:
177
- users, posts = await asyncio.gather(
178
- client.get("/users"), client.get("/posts")
179
- )
180
- return users.json(), posts.json()
181
-
182
- # Timeout
183
- async with asyncio.timeout(5.0): # 3.11+ (was asyncio.wait_for)
184
- result = await slow_operation()
185
-
186
- # Semaphore — limit concurrent ops
187
- sem = asyncio.Semaphore(10)
188
- async def limited_fetch(url: str) -> dict:
189
- async with sem:
190
- async with httpx.AsyncClient() as client:
191
- return (await client.get(url)).json()
192
-
193
- # Producer-Consumer
194
- async def producer(q: asyncio.Queue[str]):
195
- for item in data: await q.put(item)
196
- await q.put(None) # sentinel
197
-
198
- async def consumer(q: asyncio.Queue[str]):
199
- while (item := await q.get()) is not None:
200
- await process(item)
201
- q.task_done()
202
- ```
203
-
204
- ---
205
-
206
- ## Error Handling
207
-
208
- ```python
209
- # NEVER silently swallow exceptions
210
- try: result = await risky_op()
211
- except SpecificError as e: logger.error("Failed: %s", e); raise
212
- except Exception: logger.exception("Unexpected"); raise
213
-
214
- # Custom exceptions with context
215
- class ServiceError(Exception):
216
- def __init__(self, msg: str, code: int = 500, context: dict | None = None):
217
- super().__init__(msg)
218
- self.code = code; self.context = context or {}
219
-
220
- # Context managers for cleanup
221
- from contextlib import asynccontextmanager
222
- @asynccontextmanager
223
- async def managed_connection():
224
- conn = await db.connect()
225
- try: yield conn
226
- finally: await conn.close()
227
- ```
228
-
229
- ---
230
-
231
- ## Testing (pytest)
232
-
233
- ```python
234
- import pytest
235
- from httpx import AsyncClient, ASGITransport
236
-
237
- @pytest.fixture
238
- async def client():
239
- async with AsyncClient(transport=ASGITransport(app=app), base_url="http://test") as c:
240
- yield c
241
-
242
- @pytest.mark.anyio
243
- async def test_create_user(client: AsyncClient):
244
- r = await client.post("/users", json={"name": "Alice", "email": "a@b.com", "age": 25})
245
- assert r.status_code == 201
246
- assert r.json()["name"] == "Alice"
247
-
248
- # Fixtures with factories (avoid fixtures that return complex data directly)
249
- @pytest.fixture
250
- def make_user(db_session):
251
- async def _make(name="Alice", role="user"):
252
- return await User.create(db=db_session, name=name, role=role)
253
- return _make
254
- ```
255
-
256
- ---
257
-
258
- ## Project Structure
259
-
260
- ```
261
- my-api/
262
- ├── app/
263
- │ ├── main.py # FastAPI app + lifespan
264
- │ ├── models/ # SQLAlchemy ORM models
265
- │ ├── schemas/ # Pydantic request/response models
266
- │ ├── routers/ # APIRouter groups
267
- │ ├── services/ # Business logic (no FastAPI imports)
268
- │ ├── dependencies.py # Shared Depends() callables
269
- │ └── config.py # Settings via pydantic-settings
270
- ├── tests/
271
- ├── alembic/ # Migrations
272
- └── pyproject.toml
273
- ```
1
+ ---
2
+ name: python-pro
3
+ description: Python 3.12+ specialist. FastAPI, Pydantic v2, asyncio, modern types, pytest. Use when building Python APIs, data pipelines, automation, or any Python code.
4
+ allowed-tools: Read, Write, Edit, Glob, Grep
5
+ version: 3.1.0
6
+ last-updated: 2026-04-06
7
+ ---
8
+
9
+ # Python 3.12+ — Dense Reference
10
+
11
+ ## Hallucination Traps (Read First)
12
+ - ❌ `from typing import List, Dict, Optional, Union` → ✅ `list[str]`, `dict[k,v]`, `X | None`, `X | Y` (Python 3.10+)
13
+ - ❌ `user.dict()` / `user.json()` / `UserCreate.parse_obj()` → ✅ Pydantic v2: `model_dump()`, `model_dump_json()`, `model_validate()`
14
+ - ❌ Pydantic `class Config: orm_mode = True` → ✅ `model_config = {"from_attributes": True}`
15
+ - ❌ `@validator` / `@root_validator` → ✅ `@field_validator` / `@model_validator`
16
+ - ❌ `@app.on_event("startup")` → ✅ `lifespan` context manager (deprecated)
17
+ - ❌ `import requests` in async code → ✅ `httpx.AsyncClient()` (requests BLOCKS the event loop)
18
+ - ❌ `asyncio.run()` inside running loop → ✅ `await` directly or use `loop.create_task()`
19
+ - ❌ `except Exception as e: pass` → ✅ always log or re-raise
20
+
21
+ ---
22
+
23
+ ## Type System (3.12+)
24
+
25
+ ```python
26
+ # Built-in generics (3.9+) — no typing imports needed for basic types
27
+ def process(items: list[str]) -> dict[str, int]: ...
28
+ def find(user_id: int) -> User | None: ... # 3.10+ union
29
+ def parse(raw: str) -> int | float | None: ...
30
+
31
+ # Generic syntax (3.12+)
32
+ def first[T](items: list[T]) -> T | None:
33
+ return items[0] if items else None
34
+ type Point = tuple[float, float] # 3.12+ type alias
35
+
36
+ # Protocol (structural typing — duck typing with types)
37
+ from typing import Protocol, runtime_checkable
38
+ @runtime_checkable
39
+ class Renderable(Protocol):
40
+ def render(self) -> str: ...
41
+
42
+ # TypedDict — typed dict with optional keys
43
+ from typing import TypedDict, NotRequired
44
+ class UserPayload(TypedDict):
45
+ name: str; email: str
46
+ age: NotRequired[int] # optional key
47
+
48
+ # ParamSpec — preserve signatures in decorators
49
+ from typing import TypeVar, ParamSpec
50
+ from collections.abc import Callable
51
+ T = TypeVar("T"); P = ParamSpec("P")
52
+ def with_logging(func: Callable[P, T]) -> Callable[P, T]:
53
+ def wrapper(*args: P.args, **kwargs: P.kwargs) -> T:
54
+ result = func(*args, **kwargs)
55
+ return result
56
+ return wrapper
57
+ ```
58
+
59
+ ---
60
+
61
+ ## Pydantic v2
62
+
63
+ ```python
64
+ from pydantic import BaseModel, Field, field_validator, model_validator
65
+ from enum import Enum
66
+
67
+ class Role(str, Enum):
68
+ ADMIN = "admin"; USER = "user"
69
+
70
+ class UserCreate(BaseModel):
71
+ name: str = Field(..., min_length=2, max_length=100)
72
+ email: str = Field(..., pattern=r"^[\w.-]+@[\w.-]+\.\w+$")
73
+ age: int = Field(..., ge=13, le=120)
74
+ role: Role = Role.USER
75
+ tags: list[str] = Field(default_factory=list)
76
+
77
+ @field_validator("name")
78
+ @classmethod
79
+ def name_titlecase(cls, v: str) -> str:
80
+ if not v[0].isupper(): raise ValueError("Name must start with uppercase")
81
+ return v.strip()
82
+
83
+ @model_validator(mode="after")
84
+ def check_admin_age(self) -> "UserCreate":
85
+ if self.role == Role.ADMIN and self.age < 18:
86
+ raise ValueError("Admins must be 18+")
87
+ return self
88
+
89
+ class UserResponse(BaseModel):
90
+ id: int; name: str; email: str
91
+ model_config = {"from_attributes": True} # ORM mode (was orm_mode=True in v1)
92
+
93
+ # Serialization
94
+ user.model_dump() # ✅ (was .dict())
95
+ user.model_dump_json() # ✅ (was .json())
96
+ user.model_dump(exclude={"password"}, mode="json")
97
+ UserCreate.model_validate({"name": "Alice", "email": "a@b.com", "age": 30}) # ✅ (was parse_obj)
98
+ UserCreate.model_validate_json('{"name": "Bob", ...}')
99
+ ```
100
+
101
+ ---
102
+
103
+ ## FastAPI
104
+
105
+ ```python
106
+ from fastapi import FastAPI, HTTPException, Depends, Query, Path, status
107
+ from contextlib import asynccontextmanager
108
+
109
+ @asynccontextmanager
110
+ async def lifespan(app: FastAPI):
111
+ await init_db(); await redis.connect() # startup
112
+ yield
113
+ await redis.close() # shutdown
114
+
115
+ app = FastAPI(title="My API", version="1.0.0", lifespan=lifespan)
116
+
117
+ # CORS — never "*" in production
118
+ from fastapi.middleware.cors import CORSMiddleware
119
+ app.add_middleware(CORSMiddleware,
120
+ allow_origins=["https://myapp.com"], # ❌ NEVER ["*"]
121
+ allow_credentials=True, allow_methods=["GET","POST","PUT","DELETE"], allow_headers=["*"])
122
+
123
+ # Routes
124
+ @app.get("/users", response_model=list[UserResponse])
125
+ async def list_users(skip: int = Query(0, ge=0), limit: int = Query(20, le=100)) -> list[UserResponse]:
126
+ return await db.execute(select(User).offset(skip).limit(limit))
127
+
128
+ @app.post("/users", response_model=UserResponse, status_code=status.HTTP_201_CREATED)
129
+ async def create_user(payload: UserCreate) -> UserResponse:
130
+ user = User(**payload.model_dump())
131
+ db.add(user); await db.commit(); await db.refresh(user)
132
+ return user
133
+
134
+ # Dependency Injection
135
+ async def get_db() -> AsyncGenerator[AsyncSession, None]:
136
+ async with async_session() as session:
137
+ try: yield session
138
+ finally: await session.close()
139
+
140
+ async def get_current_user(token: str = Depends(oauth2_scheme), db: AsyncSession = Depends(get_db)) -> User:
141
+ payload = decode_jwt(token)
142
+ user = await db.get(User, payload["sub"])
143
+ if not user: raise HTTPException(status_code=401, detail="Invalid credentials")
144
+ return user
145
+
146
+ def require_role(role: Role):
147
+ async def checker(user: User = Depends(get_current_user)) -> User:
148
+ if user.role != role: raise HTTPException(status_code=403, detail="Forbidden")
149
+ return user
150
+ return checker
151
+
152
+ # Background Tasks
153
+ from fastapi import BackgroundTasks
154
+ @app.post("/orders")
155
+ async def create_order(order: OrderCreate, bg: BackgroundTasks) -> OrderResponse:
156
+ result = await save_order(order)
157
+ bg.add_task(send_email, result.email)
158
+ return result
159
+
160
+ # Exception handlers
161
+ from fastapi.responses import JSONResponse
162
+ @app.exception_handler(AppError)
163
+ async def app_error(request: Request, exc: AppError) -> JSONResponse:
164
+ return JSONResponse(status_code=exc.status_code, content={"error": exc.message})
165
+ ```
166
+
167
+ ---
168
+
169
+ ## Async Patterns
170
+
171
+ ```python
172
+ import asyncio, httpx
173
+
174
+ # Parallel calls — await all simultaneously
175
+ async def fetch_all() -> tuple:
176
+ async with httpx.AsyncClient() as client:
177
+ users, posts = await asyncio.gather(
178
+ client.get("/users"), client.get("/posts")
179
+ )
180
+ return users.json(), posts.json()
181
+
182
+ # Timeout
183
+ async with asyncio.timeout(5.0): # 3.11+ (was asyncio.wait_for)
184
+ result = await slow_operation()
185
+
186
+ # Semaphore — limit concurrent ops
187
+ sem = asyncio.Semaphore(10)
188
+ async def limited_fetch(url: str) -> dict:
189
+ async with sem:
190
+ async with httpx.AsyncClient() as client:
191
+ return (await client.get(url)).json()
192
+
193
+ # Producer-Consumer
194
+ async def producer(q: asyncio.Queue[str]):
195
+ for item in data: await q.put(item)
196
+ await q.put(None) # sentinel
197
+
198
+ async def consumer(q: asyncio.Queue[str]):
199
+ while (item := await q.get()) is not None:
200
+ await process(item)
201
+ q.task_done()
202
+ ```
203
+
204
+ ---
205
+
206
+ ## Error Handling
207
+
208
+ ```python
209
+ # NEVER silently swallow exceptions
210
+ try: result = await risky_op()
211
+ except SpecificError as e: logger.error("Failed: %s", e); raise
212
+ except Exception: logger.exception("Unexpected"); raise
213
+
214
+ # Custom exceptions with context
215
+ class ServiceError(Exception):
216
+ def __init__(self, msg: str, code: int = 500, context: dict | None = None):
217
+ super().__init__(msg)
218
+ self.code = code; self.context = context or {}
219
+
220
+ # Context managers for cleanup
221
+ from contextlib import asynccontextmanager
222
+ @asynccontextmanager
223
+ async def managed_connection():
224
+ conn = await db.connect()
225
+ try: yield conn
226
+ finally: await conn.close()
227
+ ```
228
+
229
+ ---
230
+
231
+ ## Testing (pytest)
232
+
233
+ ```python
234
+ import pytest
235
+ from httpx import AsyncClient, ASGITransport
236
+
237
+ @pytest.fixture
238
+ async def client():
239
+ async with AsyncClient(transport=ASGITransport(app=app), base_url="http://test") as c:
240
+ yield c
241
+
242
+ @pytest.mark.anyio
243
+ async def test_create_user(client: AsyncClient):
244
+ r = await client.post("/users", json={"name": "Alice", "email": "a@b.com", "age": 25})
245
+ assert r.status_code == 201
246
+ assert r.json()["name"] == "Alice"
247
+
248
+ # Fixtures with factories (avoid fixtures that return complex data directly)
249
+ @pytest.fixture
250
+ def make_user(db_session):
251
+ async def _make(name="Alice", role="user"):
252
+ return await User.create(db=db_session, name=name, role=role)
253
+ return _make
254
+ ```
255
+
256
+ ---
257
+
258
+ ## Project Structure
259
+
260
+ ```
261
+ my-api/
262
+ ├── app/
263
+ │ ├── main.py # FastAPI app + lifespan
264
+ │ ├── models/ # SQLAlchemy ORM models
265
+ │ ├── schemas/ # Pydantic request/response models
266
+ │ ├── routers/ # APIRouter groups
267
+ │ ├── services/ # Business logic (no FastAPI imports)
268
+ │ ├── dependencies.py # Shared Depends() callables
269
+ │ └── config.py # Settings via pydantic-settings
270
+ ├── tests/
271
+ ├── alembic/ # Migrations
272
+ └── pyproject.toml
273
+ ```
274
274
 
275
275
 
276
276
  ---
@@ -312,4 +312,12 @@ Review these questions before confirming output:
312
312
 
313
313
  **CRITICAL:** You must follow a strict "evidence-based closeout" state machine.
314
314
  - ❌ **Forbidden:** Declaring a task complete because the output "looks correct."
315
- - ✅ **Required:** You are explicitly forbidden from finalizing any task without providing **concrete evidence** (terminal output, passing tests, compile success, or equivalent proof) that your output works as intended.
315
+ - ✅ **Required:** You are explicitly forbidden from finalizing any task without providing **concrete evidence** (terminal output, passing tests, compile success, or equivalent proof) that your output works as intended.
316
+
317
+
318
+ ## Pre-Flight Checklist
319
+ - [ ] Have I reviewed the user's specific constraints and requests?
320
+ - [ ] Have I checked the environment for relevant existing implementations?
321
+
322
+ ## VBC Protocol (Verification-Before-Completion)
323
+ You MUST verify existing code signatures and variables before attempting to modify or call them. No hallucination is permitted.