@martinffx/atelier 1.4.0 → 3.0.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.
- package/CHANGELOG.md +38 -0
- package/README.md +95 -220
- package/agents/architect.md +6 -6
- package/agents/oracle.md +1 -1
- package/agents/{recon.md → sentinel.md} +3 -3
- package/dist/atelier.js +167 -26
- package/package.json +2 -1
- package/skills/atelier-orchestrator/SKILL.md +180 -0
- package/skills/atelier-setup/SKILL.md +80 -0
- package/skills/code-review/SKILL.md +2 -2
- package/skills/code-review/references/reviewers.md +3 -3
- package/skills/code-review/references/rq.md +9 -9
- package/skills/code-subagents/SKILL.md +44 -75
- package/skills/code-subagents/references/batch-reviewer-prompt.md +44 -0
- package/skills/code-subagents/references/implementor-prompt.md +10 -11
- package/skills/spec-brainstorm/SKILL.md +21 -16
- package/skills/spec-finish/SKILL.md +14 -14
- package/skills/spec-implement/SKILL.md +42 -42
- package/skills/spec-plan/SKILL.md +72 -26
- package/skills/spec-plan/references/plan_template.md +77 -0
- package/skills/code-subagents/references/code-quality-reviewer-prompt.md +0 -48
- package/skills/code-subagents/references/spec-reviewer-prompt.md +0 -62
- package/skills/python-architecture/SKILL.md +0 -148
- package/skills/python-architecture/references/data-modeling.md +0 -558
- package/skills/python-architecture/references/ddd.md +0 -569
- package/skills/python-architecture/references/functional-core.md +0 -337
- package/skills/python-build-tools/SKILL.md +0 -153
- package/skills/python-build-tools/references/basedpyright.md +0 -321
- package/skills/python-build-tools/references/ruff.md +0 -225
- package/skills/python-build-tools/references/uv.md +0 -257
- package/skills/python-fastapi/SKILL.md +0 -184
- package/skills/python-fastapi/references/api-design.md +0 -563
- package/skills/python-fastapi/references/dependencies.md +0 -479
- package/skills/python-fastapi/references/middleware.md +0 -475
- package/skills/python-fastapi/references/validation.md +0 -497
- package/skills/python-modern-python/SKILL.md +0 -201
- package/skills/python-modern-python/references/async.md +0 -76
- package/skills/python-modern-python/references/pattern-matching.md +0 -89
- package/skills/python-modern-python/references/typing.md +0 -96
- package/skills/python-monorepo/SKILL.md +0 -146
- package/skills/python-monorepo/references/docker.md +0 -515
- package/skills/python-monorepo/references/namespace-packages.md +0 -426
- package/skills/python-monorepo/references/workspace-config.md +0 -341
- package/skills/python-sqlalchemy/SKILL.md +0 -119
- package/skills/python-sqlalchemy/references/async.md +0 -51
- package/skills/python-sqlalchemy/references/models.md +0 -67
- package/skills/python-sqlalchemy/references/queries.md +0 -57
- package/skills/python-temporal/SKILL.md +0 -128
- package/skills/python-temporal/references/patterns.md +0 -87
- package/skills/python-temporal/references/testing.md +0 -54
- package/skills/python-testing/SKILL.md +0 -161
- package/skills/python-testing/references/boundaries.md +0 -449
- package/skills/python-testing/references/mocking.md +0 -449
- package/skills/python-testing/references/pytest.md +0 -524
- package/skills/spec-orchestrator/SKILL.md +0 -145
- package/skills/typescript-api-design/SKILL.md +0 -396
- package/skills/typescript-api-design/references/error-responses.md +0 -469
- package/skills/typescript-build-tools/SKILL.md +0 -447
- package/skills/typescript-build-tools/references/biome.md +0 -436
- package/skills/typescript-build-tools/references/bun.md +0 -432
- package/skills/typescript-build-tools/references/turborepo.md +0 -426
- package/skills/typescript-build-tools/references/vitest.md +0 -518
- package/skills/typescript-drizzle-orm/SKILL.md +0 -398
- package/skills/typescript-drizzle-orm/references/cloudflare.md +0 -392
- package/skills/typescript-drizzle-orm/references/entity-pattern.md +0 -412
- package/skills/typescript-drizzle-orm/references/postgresql.md +0 -191
- package/skills/typescript-drizzle-orm/references/repository-pattern.md +0 -479
- package/skills/typescript-drizzle-orm/references/sqlite.md +0 -291
- package/skills/typescript-dynamodb-toolbox/SKILL.md +0 -370
- package/skills/typescript-dynamodb-toolbox/references/entity-layer.md +0 -574
- package/skills/typescript-dynamodb-toolbox/references/error-handling.md +0 -495
- package/skills/typescript-dynamodb-toolbox/references/modeling.md +0 -332
- package/skills/typescript-dynamodb-toolbox/references/repository-layer.md +0 -631
- package/skills/typescript-dynamodb-toolbox/references/testing.md +0 -718
- package/skills/typescript-dynamodb-toolbox/references/transactions.md +0 -423
- package/skills/typescript-effect-ts/SKILL.md +0 -341
- package/skills/typescript-effect-ts/references/core.md +0 -412
- package/skills/typescript-effect-ts/references/error-handling.md +0 -468
- package/skills/typescript-effect-ts/references/resources.md +0 -476
- package/skills/typescript-effect-ts/references/schema.md +0 -536
- package/skills/typescript-effect-ts/references/services.md +0 -461
- package/skills/typescript-fastify/SKILL.md +0 -405
- package/skills/typescript-fastify/references/plugins.md +0 -329
- package/skills/typescript-fastify/references/typeid.md +0 -315
- package/skills/typescript-functional-patterns/SKILL.md +0 -402
- package/skills/typescript-functional-patterns/references/adts.md +0 -497
- package/skills/typescript-functional-patterns/references/branded-types.md +0 -542
- package/skills/typescript-functional-patterns/references/migration-guide.md +0 -695
- package/skills/typescript-functional-patterns/references/option-result.md +0 -585
- package/skills/typescript-testing/SKILL.md +0 -353
- package/skills/typescript-testing/references/mocking.md +0 -675
- package/skills/typescript-testing/references/msw.md +0 -852
- package/skills/typescript-testing/references/snapshot-testing.md +0 -774
|
@@ -1,524 +0,0 @@
|
|
|
1
|
-
# pytest Configuration and Patterns
|
|
2
|
-
|
|
3
|
-
## Configuration (pyproject.toml)
|
|
4
|
-
|
|
5
|
-
### Basic Setup
|
|
6
|
-
|
|
7
|
-
```toml
|
|
8
|
-
[tool.pytest.ini_options]
|
|
9
|
-
testpaths = ["tests"]
|
|
10
|
-
python_files = ["test_*.py", "*_test.py"]
|
|
11
|
-
python_classes = ["Test*"]
|
|
12
|
-
python_functions = ["test_*"]
|
|
13
|
-
addopts = [
|
|
14
|
-
"-ra", # Show summary of all test outcomes
|
|
15
|
-
"--strict-markers", # Fail on unknown markers
|
|
16
|
-
"--strict-config", # Fail on invalid config
|
|
17
|
-
"-v", # Verbose output
|
|
18
|
-
]
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
### With Coverage
|
|
22
|
-
|
|
23
|
-
```toml
|
|
24
|
-
[tool.pytest.ini_options]
|
|
25
|
-
testpaths = ["tests"]
|
|
26
|
-
addopts = [
|
|
27
|
-
"-ra",
|
|
28
|
-
"--strict-markers",
|
|
29
|
-
"--cov=src",
|
|
30
|
-
"--cov-report=term-missing",
|
|
31
|
-
"--cov-report=html",
|
|
32
|
-
"--cov-fail-under=80",
|
|
33
|
-
]
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
### Markers
|
|
37
|
-
|
|
38
|
-
```toml
|
|
39
|
-
[tool.pytest.ini_options]
|
|
40
|
-
markers = [
|
|
41
|
-
"unit: unit tests (no I/O)",
|
|
42
|
-
"integration: integration tests (with I/O)",
|
|
43
|
-
"slow: slow tests (takes >1s)",
|
|
44
|
-
"db: database tests",
|
|
45
|
-
]
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
## Fixtures
|
|
49
|
-
|
|
50
|
-
### Database Session
|
|
51
|
-
|
|
52
|
-
```python
|
|
53
|
-
import pytest
|
|
54
|
-
from sqlalchemy import create_engine
|
|
55
|
-
from sqlalchemy.orm import sessionmaker
|
|
56
|
-
|
|
57
|
-
@pytest.fixture
|
|
58
|
-
def test_db():
|
|
59
|
-
"""In-memory test database"""
|
|
60
|
-
engine = create_engine("sqlite:///:memory:")
|
|
61
|
-
Base.metadata.create_all(engine)
|
|
62
|
-
|
|
63
|
-
SessionLocal = sessionmaker(bind=engine)
|
|
64
|
-
db = SessionLocal()
|
|
65
|
-
|
|
66
|
-
try:
|
|
67
|
-
yield db
|
|
68
|
-
finally:
|
|
69
|
-
db.close()
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
### Application Client
|
|
73
|
-
|
|
74
|
-
```python
|
|
75
|
-
import pytest
|
|
76
|
-
from fastapi.testclient import TestClient
|
|
77
|
-
|
|
78
|
-
@pytest.fixture
|
|
79
|
-
def test_client():
|
|
80
|
-
"""FastAPI test client"""
|
|
81
|
-
return TestClient(app)
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
### Auto-Use Fixtures for Setup/Teardown
|
|
85
|
-
|
|
86
|
-
```python
|
|
87
|
-
@pytest.fixture(autouse=True)
|
|
88
|
-
def reset_db(test_db):
|
|
89
|
-
"""Reset database before each test"""
|
|
90
|
-
Base.metadata.drop_all(bind=test_db.bind)
|
|
91
|
-
Base.metadata.create_all(bind=test_db.bind)
|
|
92
|
-
```
|
|
93
|
-
|
|
94
|
-
### Fixture Scope
|
|
95
|
-
|
|
96
|
-
```python
|
|
97
|
-
@pytest.fixture(scope="function") # Default: per test
|
|
98
|
-
def data():
|
|
99
|
-
...
|
|
100
|
-
|
|
101
|
-
@pytest.fixture(scope="module") # Per test file
|
|
102
|
-
def client():
|
|
103
|
-
...
|
|
104
|
-
|
|
105
|
-
@pytest.fixture(scope="session") # For entire test run
|
|
106
|
-
def config():
|
|
107
|
-
...
|
|
108
|
-
```
|
|
109
|
-
|
|
110
|
-
### Parametrized Fixtures
|
|
111
|
-
|
|
112
|
-
```python
|
|
113
|
-
@pytest.fixture(params=[
|
|
114
|
-
{"name": "Alice", "age": 25},
|
|
115
|
-
{"name": "Bob", "age": 30},
|
|
116
|
-
{"name": "Charlie", "age": 35},
|
|
117
|
-
])
|
|
118
|
-
def user_data(request):
|
|
119
|
-
"""Fixture provides multiple inputs"""
|
|
120
|
-
return request.param
|
|
121
|
-
|
|
122
|
-
def test_user_creation(user_data):
|
|
123
|
-
"""Runs 3 times with different data"""
|
|
124
|
-
user = User(**user_data)
|
|
125
|
-
assert user.name is not None
|
|
126
|
-
```
|
|
127
|
-
|
|
128
|
-
### Fixture Dependencies
|
|
129
|
-
|
|
130
|
-
```python
|
|
131
|
-
@pytest.fixture
|
|
132
|
-
def test_db():
|
|
133
|
-
"""Database fixture"""
|
|
134
|
-
engine = create_engine("sqlite:///:memory:")
|
|
135
|
-
Base.metadata.create_all(engine)
|
|
136
|
-
SessionLocal = sessionmaker(bind=engine)
|
|
137
|
-
return SessionLocal()
|
|
138
|
-
|
|
139
|
-
@pytest.fixture
|
|
140
|
-
def user_repository(test_db):
|
|
141
|
-
"""Repository depends on database"""
|
|
142
|
-
return UserRepository(test_db)
|
|
143
|
-
|
|
144
|
-
def test_repository_save(user_repository):
|
|
145
|
-
"""Test uses repository (which uses database)"""
|
|
146
|
-
user = User(id=1, name="Alice")
|
|
147
|
-
user_repository.save(user)
|
|
148
|
-
assert user_repository.get(1) is not None
|
|
149
|
-
```
|
|
150
|
-
|
|
151
|
-
## Running Tests
|
|
152
|
-
|
|
153
|
-
### Basic Commands
|
|
154
|
-
|
|
155
|
-
```bash
|
|
156
|
-
# Run all tests
|
|
157
|
-
pytest
|
|
158
|
-
|
|
159
|
-
# Run specific file
|
|
160
|
-
pytest tests/test_entities.py
|
|
161
|
-
|
|
162
|
-
# Run specific test
|
|
163
|
-
pytest tests/test_entities.py::test_user_creation
|
|
164
|
-
|
|
165
|
-
# Run with pattern
|
|
166
|
-
pytest tests/test_*.py
|
|
167
|
-
|
|
168
|
-
# Verbose output
|
|
169
|
-
pytest -v
|
|
170
|
-
|
|
171
|
-
# Very verbose (shows parameters)
|
|
172
|
-
pytest -vv
|
|
173
|
-
```
|
|
174
|
-
|
|
175
|
-
### Filtering Tests
|
|
176
|
-
|
|
177
|
-
```bash
|
|
178
|
-
# Stop on first failure
|
|
179
|
-
pytest -x
|
|
180
|
-
|
|
181
|
-
# Stop after N failures
|
|
182
|
-
pytest --maxfail=3
|
|
183
|
-
|
|
184
|
-
# Show print statements
|
|
185
|
-
pytest -s
|
|
186
|
-
|
|
187
|
-
# Show local variables on failure
|
|
188
|
-
pytest -l
|
|
189
|
-
|
|
190
|
-
# Show durations of slowest tests
|
|
191
|
-
pytest --durations=10
|
|
192
|
-
```
|
|
193
|
-
|
|
194
|
-
### Markers
|
|
195
|
-
|
|
196
|
-
```bash
|
|
197
|
-
# Run only unit tests
|
|
198
|
-
pytest -m unit
|
|
199
|
-
|
|
200
|
-
# Skip slow tests
|
|
201
|
-
pytest -m "not slow"
|
|
202
|
-
|
|
203
|
-
# Run integration tests
|
|
204
|
-
pytest -m integration
|
|
205
|
-
|
|
206
|
-
# Run tests matching pattern
|
|
207
|
-
pytest -m "unit or integration"
|
|
208
|
-
```
|
|
209
|
-
|
|
210
|
-
### Coverage
|
|
211
|
-
|
|
212
|
-
```bash
|
|
213
|
-
# Generate coverage report
|
|
214
|
-
pytest --cov=src
|
|
215
|
-
|
|
216
|
-
# Show missing lines
|
|
217
|
-
pytest --cov=src --cov-report=term-missing
|
|
218
|
-
|
|
219
|
-
# Generate HTML report
|
|
220
|
-
pytest --cov=src --cov-report=html
|
|
221
|
-
# Open htmlcov/index.html in browser
|
|
222
|
-
|
|
223
|
-
# Fail if below threshold
|
|
224
|
-
pytest --cov=src --cov-fail-under=80
|
|
225
|
-
```
|
|
226
|
-
|
|
227
|
-
## Parametrize
|
|
228
|
-
|
|
229
|
-
### Multiple Inputs
|
|
230
|
-
|
|
231
|
-
```python
|
|
232
|
-
@pytest.mark.parametrize("input,expected", [
|
|
233
|
-
(1, 2),
|
|
234
|
-
(2, 4),
|
|
235
|
-
(3, 6),
|
|
236
|
-
(4, 8),
|
|
237
|
-
])
|
|
238
|
-
def test_double(input, expected):
|
|
239
|
-
assert double(input) == expected
|
|
240
|
-
```
|
|
241
|
-
|
|
242
|
-
### Multiple Parameters
|
|
243
|
-
|
|
244
|
-
```python
|
|
245
|
-
@pytest.mark.parametrize("x,y,expected", [
|
|
246
|
-
(1, 2, 3),
|
|
247
|
-
(2, 3, 5),
|
|
248
|
-
(5, 5, 10),
|
|
249
|
-
])
|
|
250
|
-
def test_add(x, y, expected):
|
|
251
|
-
assert add(x, y) == expected
|
|
252
|
-
```
|
|
253
|
-
|
|
254
|
-
### Parametrize Multiple Test Values
|
|
255
|
-
|
|
256
|
-
```python
|
|
257
|
-
@pytest.mark.parametrize("value", [
|
|
258
|
-
"alice@example.com",
|
|
259
|
-
"bob@example.com",
|
|
260
|
-
"charlie@example.com",
|
|
261
|
-
])
|
|
262
|
-
def test_valid_email(value):
|
|
263
|
-
assert is_valid_email(value)
|
|
264
|
-
```
|
|
265
|
-
|
|
266
|
-
### Combining Parametrize
|
|
267
|
-
|
|
268
|
-
```python
|
|
269
|
-
@pytest.mark.parametrize("user_type", ["admin", "user", "guest"])
|
|
270
|
-
@pytest.mark.parametrize("resource", ["posts", "comments", "users"])
|
|
271
|
-
def test_permissions(user_type, resource):
|
|
272
|
-
"""Tests all combinations (3×3 = 9 tests)"""
|
|
273
|
-
has_access = check_access(user_type, resource)
|
|
274
|
-
assert has_access is not None
|
|
275
|
-
```
|
|
276
|
-
|
|
277
|
-
## Markers
|
|
278
|
-
|
|
279
|
-
### Built-in Markers
|
|
280
|
-
|
|
281
|
-
```python
|
|
282
|
-
@pytest.mark.skip
|
|
283
|
-
def test_not_ready():
|
|
284
|
-
"""Skip this test"""
|
|
285
|
-
...
|
|
286
|
-
|
|
287
|
-
@pytest.mark.skip(reason="Not implemented yet")
|
|
288
|
-
def test_future():
|
|
289
|
-
"""Skip with reason"""
|
|
290
|
-
...
|
|
291
|
-
|
|
292
|
-
@pytest.mark.skipif(sys.version_info < (3, 10), reason="Requires 3.10+")
|
|
293
|
-
def test_new_syntax():
|
|
294
|
-
"""Skip conditionally"""
|
|
295
|
-
...
|
|
296
|
-
|
|
297
|
-
@pytest.mark.xfail
|
|
298
|
-
def test_known_bug():
|
|
299
|
-
"""Mark as expected to fail"""
|
|
300
|
-
...
|
|
301
|
-
```
|
|
302
|
-
|
|
303
|
-
### Custom Markers
|
|
304
|
-
|
|
305
|
-
```python
|
|
306
|
-
@pytest.mark.unit
|
|
307
|
-
def test_entity():
|
|
308
|
-
...
|
|
309
|
-
|
|
310
|
-
@pytest.mark.integration
|
|
311
|
-
def test_with_database():
|
|
312
|
-
...
|
|
313
|
-
|
|
314
|
-
@pytest.mark.slow
|
|
315
|
-
def test_expensive_computation():
|
|
316
|
-
...
|
|
317
|
-
|
|
318
|
-
@pytest.mark.db
|
|
319
|
-
def test_with_db():
|
|
320
|
-
...
|
|
321
|
-
```
|
|
322
|
-
|
|
323
|
-
## Test Organization
|
|
324
|
-
|
|
325
|
-
### Structure by Layer
|
|
326
|
-
|
|
327
|
-
```
|
|
328
|
-
tests/
|
|
329
|
-
├── unit/
|
|
330
|
-
│ ├── test_entities.py # Entity tests
|
|
331
|
-
│ ├── test_services.py # Service tests (mocked)
|
|
332
|
-
│ └── test_value_objects.py # Value object tests
|
|
333
|
-
├── integration/
|
|
334
|
-
│ ├── test_repositories.py # Repository tests (with DB)
|
|
335
|
-
│ └── test_endpoints.py # Router tests (with client)
|
|
336
|
-
└── fixtures.py # Shared fixtures
|
|
337
|
-
```
|
|
338
|
-
|
|
339
|
-
### conftest.py for Shared Fixtures
|
|
340
|
-
|
|
341
|
-
```python
|
|
342
|
-
# tests/conftest.py
|
|
343
|
-
import pytest
|
|
344
|
-
from sqlalchemy import create_engine
|
|
345
|
-
from sqlalchemy.orm import sessionmaker
|
|
346
|
-
from fastapi.testclient import TestClient
|
|
347
|
-
|
|
348
|
-
@pytest.fixture
|
|
349
|
-
def test_db():
|
|
350
|
-
"""Shared database fixture"""
|
|
351
|
-
engine = create_engine("sqlite:///:memory:")
|
|
352
|
-
Base.metadata.create_all(engine)
|
|
353
|
-
SessionLocal = sessionmaker(bind=engine)
|
|
354
|
-
db = SessionLocal()
|
|
355
|
-
try:
|
|
356
|
-
yield db
|
|
357
|
-
finally:
|
|
358
|
-
db.close()
|
|
359
|
-
|
|
360
|
-
@pytest.fixture
|
|
361
|
-
def test_client():
|
|
362
|
-
"""Shared test client"""
|
|
363
|
-
return TestClient(app)
|
|
364
|
-
|
|
365
|
-
# tests/test_entities.py
|
|
366
|
-
def test_product_creation(test_db):
|
|
367
|
-
"""Uses fixture from conftest.py"""
|
|
368
|
-
...
|
|
369
|
-
```
|
|
370
|
-
|
|
371
|
-
### Naming Conventions
|
|
372
|
-
|
|
373
|
-
```python
|
|
374
|
-
# File names
|
|
375
|
-
test_entities.py # Tests for entities module
|
|
376
|
-
test_create_product.py # Tests for specific feature
|
|
377
|
-
|
|
378
|
-
# Test class (optional grouping)
|
|
379
|
-
class TestProduct:
|
|
380
|
-
def test_creation(self):
|
|
381
|
-
...
|
|
382
|
-
|
|
383
|
-
def test_validation(self):
|
|
384
|
-
...
|
|
385
|
-
|
|
386
|
-
# Test function names
|
|
387
|
-
def test_product_creation(): # What is tested
|
|
388
|
-
def test_product_with_discount(): # Behavior variant
|
|
389
|
-
def test_product_raises_on_invalid_price(): # Error case
|
|
390
|
-
```
|
|
391
|
-
|
|
392
|
-
## Assertions and Context
|
|
393
|
-
|
|
394
|
-
### assert with Message
|
|
395
|
-
|
|
396
|
-
```python
|
|
397
|
-
def test_with_message():
|
|
398
|
-
result = calculate()
|
|
399
|
-
assert result == 42, f"Expected 42 but got {result}"
|
|
400
|
-
```
|
|
401
|
-
|
|
402
|
-
### pytest.raises
|
|
403
|
-
|
|
404
|
-
```python
|
|
405
|
-
def test_raises_error():
|
|
406
|
-
with pytest.raises(ValueError):
|
|
407
|
-
invalid_operation()
|
|
408
|
-
|
|
409
|
-
def test_raises_with_match():
|
|
410
|
-
with pytest.raises(ValueError, match="Invalid price"):
|
|
411
|
-
Product(price=-10)
|
|
412
|
-
|
|
413
|
-
def test_raises_with_check():
|
|
414
|
-
with pytest.raises(ValueError) as exc_info:
|
|
415
|
-
invalid_operation()
|
|
416
|
-
assert "specific message" in str(exc_info.value)
|
|
417
|
-
```
|
|
418
|
-
|
|
419
|
-
### pytest.approx for Floats
|
|
420
|
-
|
|
421
|
-
```python
|
|
422
|
-
def test_float_calculation():
|
|
423
|
-
result = expensive_calculation()
|
|
424
|
-
# Avoid exact equality with floats
|
|
425
|
-
assert result == pytest.approx(3.14159, abs=0.0001)
|
|
426
|
-
```
|
|
427
|
-
|
|
428
|
-
### Comparing Collections
|
|
429
|
-
|
|
430
|
-
```python
|
|
431
|
-
def test_lists():
|
|
432
|
-
result = get_items()
|
|
433
|
-
assert result == [1, 2, 3]
|
|
434
|
-
assert 2 in result
|
|
435
|
-
assert len(result) == 3
|
|
436
|
-
|
|
437
|
-
def test_dicts():
|
|
438
|
-
result = get_data()
|
|
439
|
-
assert result == {"name": "Alice", "age": 25}
|
|
440
|
-
assert result["name"] == "Alice"
|
|
441
|
-
assert "email" not in result
|
|
442
|
-
```
|
|
443
|
-
|
|
444
|
-
## Debugging Failed Tests
|
|
445
|
-
|
|
446
|
-
### Print Debugging
|
|
447
|
-
|
|
448
|
-
```bash
|
|
449
|
-
# Show print statements
|
|
450
|
-
pytest -s
|
|
451
|
-
|
|
452
|
-
# Show print + traceback
|
|
453
|
-
pytest -s -vv
|
|
454
|
-
|
|
455
|
-
# Show local variables
|
|
456
|
-
pytest -l
|
|
457
|
-
|
|
458
|
-
# Full diff for collections
|
|
459
|
-
pytest -vv --tb=short
|
|
460
|
-
```
|
|
461
|
-
|
|
462
|
-
### Using pdb
|
|
463
|
-
|
|
464
|
-
```python
|
|
465
|
-
def test_with_debugger():
|
|
466
|
-
result = complex_operation()
|
|
467
|
-
# Drop into debugger on failure
|
|
468
|
-
import pdb; pdb.set_trace()
|
|
469
|
-
assert result == expected
|
|
470
|
-
```
|
|
471
|
-
|
|
472
|
-
### Test Reports
|
|
473
|
-
|
|
474
|
-
```bash
|
|
475
|
-
# Generate JUnit XML (for CI)
|
|
476
|
-
pytest --junit-xml=report.xml
|
|
477
|
-
|
|
478
|
-
# Generate JSON report
|
|
479
|
-
pytest --json-report --json-report-file=report.json
|
|
480
|
-
|
|
481
|
-
# Generate HTML report
|
|
482
|
-
pytest --html=report.html
|
|
483
|
-
```
|
|
484
|
-
|
|
485
|
-
## Performance Optimization
|
|
486
|
-
|
|
487
|
-
### Profile Test Execution
|
|
488
|
-
|
|
489
|
-
```bash
|
|
490
|
-
# Show slowest tests
|
|
491
|
-
pytest --durations=10
|
|
492
|
-
|
|
493
|
-
# Show all tests sorted by duration
|
|
494
|
-
pytest --durations=0
|
|
495
|
-
```
|
|
496
|
-
|
|
497
|
-
### Parallelize Tests
|
|
498
|
-
|
|
499
|
-
```bash
|
|
500
|
-
# Install pytest-xdist
|
|
501
|
-
pip install pytest-xdist
|
|
502
|
-
|
|
503
|
-
# Run tests in parallel (use N workers)
|
|
504
|
-
pytest -n auto
|
|
505
|
-
pytest -n 4
|
|
506
|
-
```
|
|
507
|
-
|
|
508
|
-
### Fixture Optimization
|
|
509
|
-
|
|
510
|
-
```python
|
|
511
|
-
# SLOW: Creates database for every test
|
|
512
|
-
@pytest.fixture(scope="function")
|
|
513
|
-
def test_db():
|
|
514
|
-
engine = create_engine("sqlite:///:memory:")
|
|
515
|
-
Base.metadata.create_all(engine)
|
|
516
|
-
...
|
|
517
|
-
|
|
518
|
-
# FAST: Creates once per session (if tests don't modify schema)
|
|
519
|
-
@pytest.fixture(scope="session")
|
|
520
|
-
def test_db():
|
|
521
|
-
engine = create_engine("sqlite:///:memory:")
|
|
522
|
-
Base.metadata.create_all(engine)
|
|
523
|
-
...
|
|
524
|
-
```
|
|
@@ -1,145 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: spec-orchestrator
|
|
3
|
-
description: >
|
|
4
|
-
Skill routing and workflow orchestration. Routes to correct spec skill based on task type.
|
|
5
|
-
Establishes discipline and manages transitions between workflow phases. Use when starting
|
|
6
|
-
any conversation or task to determine which spec skill applies.
|
|
7
|
-
user-invocable: false
|
|
8
|
-
---
|
|
9
|
-
|
|
10
|
-
<EXTREMELY-IMPORTANT>
|
|
11
|
-
If you think there is even a 1% chance a skill might apply to what you are doing, you ABSOLUTELY
|
|
12
|
-
MUST invoke the skill.
|
|
13
|
-
|
|
14
|
-
IF A SKILL APPLIES TO YOUR TASK, YOU DO NOT HAVE A CHOICE. YOU MUST USE IT.
|
|
15
|
-
|
|
16
|
-
This is not negotiable. This is not optional. You cannot rationalize your way out of this.
|
|
17
|
-
</EXTREMELY-IMPORTANT>
|
|
18
|
-
|
|
19
|
-
# Spec Workflow
|
|
20
|
-
|
|
21
|
-
You have skills. You MUST use them. Not "should." Not "when convenient." MUST.
|
|
22
|
-
|
|
23
|
-
Invoke relevant skills BEFORE any response or action. Even a 1% chance a skill might apply
|
|
24
|
-
means you invoke it. If an invoked skill turns out to be wrong for the situation, you don't
|
|
25
|
-
need to follow it. But you must check.
|
|
26
|
-
|
|
27
|
-
## The One Rule
|
|
28
|
-
|
|
29
|
-
**Never write code until the human has reviewed and approved a written plan.**
|
|
30
|
-
|
|
31
|
-
Every project goes through this process. A todo list, a single-function utility, a config
|
|
32
|
-
change — all of them. "Simple" projects are where unexamined assumptions cause the most
|
|
33
|
-
wasted work. The spec can be short, the plan can be brief, but you MUST present them
|
|
34
|
-
and get approval.
|
|
35
|
-
|
|
36
|
-
## Artifacts
|
|
37
|
-
|
|
38
|
-
Every feature produces two artifacts in `docs/specs/YYYY-MM-DD-<feature>/`:
|
|
39
|
-
|
|
40
|
-
```
|
|
41
|
-
design.md ← spec-brainstorm (requirements + research + architecture)
|
|
42
|
-
plan.json ← spec-plan (tasks, dependencies)
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
## Skill Routing
|
|
46
|
-
|
|
47
|
-
```
|
|
48
|
-
spec-brainstorm → Discovery + design + architecture → design.md
|
|
49
|
-
spec-plan → Implementation plan + tasks → plan.json
|
|
50
|
-
spec-implement → Execute tasks, track progress, report
|
|
51
|
-
spec-finish → Post-implementation validation
|
|
52
|
-
code-subagents → Parallel dispatch, two-stage review
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
### "Create a spec for X" / Build / Add Feature
|
|
56
|
-
|
|
57
|
-
```
|
|
58
|
-
spec-brainstorm → spec-plan → spec-implement → spec-finish
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
### Fix Complex Bug / Refactor
|
|
62
|
-
|
|
63
|
-
```
|
|
64
|
-
spec-brainstorm (research-heavy) → spec-plan (targeted) → spec-implement
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
### Quick Fix / Trivial Change
|
|
68
|
-
|
|
69
|
-
If genuinely trivial (typo, single-line config, variable rename) — skip the pipeline.
|
|
70
|
-
But be honest. If there's any doubt, plan it.
|
|
71
|
-
|
|
72
|
-
## Hard Transitions
|
|
73
|
-
|
|
74
|
-
| After completing... | The ONLY next step is... |
|
|
75
|
-
|---------------------|--------------------------|
|
|
76
|
-
| spec-brainstorm | spec-plan |
|
|
77
|
-
| spec-plan | spec-implement |
|
|
78
|
-
| spec-implement | spec-finish |
|
|
79
|
-
|
|
80
|
-
Do NOT jump from requirements to code. Do NOT jump from research to implementation.
|
|
81
|
-
|
|
82
|
-
## Iteration Patterns
|
|
83
|
-
|
|
84
|
-
The workflow is not purely linear. Expect backflows:
|
|
85
|
-
|
|
86
|
-
### Research → Research (discovery loop)
|
|
87
|
-
- Brainstorm reveals new requirements → loop back to discovery phase
|
|
88
|
-
- Human adds new scope mid-brainstorm → continue discovery
|
|
89
|
-
|
|
90
|
-
### Plan → Research (design flaw)
|
|
91
|
-
- Planning reveals design assumptions are wrong → back to brainstorm
|
|
92
|
-
- Tasks can't be decomposed without more context → back to brainstorm
|
|
93
|
-
|
|
94
|
-
### Implement → Plan (missing tasks)
|
|
95
|
-
- Implementation reveals missing tasks → update plan.json
|
|
96
|
-
- Blocked on dependency not in plan → back to plan
|
|
97
|
-
|
|
98
|
-
### Implement → Research (fundamental issue)
|
|
99
|
-
- Implementation reveals design is fundamentally wrong → back to brainstorm
|
|
100
|
-
- "This can't work as designed" → back to brainstorm
|
|
101
|
-
|
|
102
|
-
### Finish → Implement (bugs found)
|
|
103
|
-
- Validation finds bugs → back to implement
|
|
104
|
-
- Tests failing → back to implement
|
|
105
|
-
|
|
106
|
-
### When to escalate
|
|
107
|
-
If you loop 2+ times on the same issue, stop and ask the human:
|
|
108
|
-
|
|
109
|
-
> "We've looped on [issue] twice. Should we reconsider the approach?"
|
|
110
|
-
|
|
111
|
-
## Red Flags — You Are Rationalizing
|
|
112
|
-
|
|
113
|
-
| What you're thinking | Why it's wrong |
|
|
114
|
-
|----------------------|----------------|
|
|
115
|
-
| "This is too simple for a plan" | Simple tasks have the most unexamined assumptions |
|
|
116
|
-
| "I already know how to do this" | Knowing how ≠ having the human's approval for how |
|
|
117
|
-
| "The human seems impatient" | Wasting time on wrong code is worse than planning |
|
|
118
|
-
| "I'll just do a quick prototype" | Prototypes become production. Plan it. |
|
|
119
|
-
| "I need to explore the code first" | That's the brainstorm phase. Write it in design.md. |
|
|
120
|
-
| "Let me just fix this one thing" | One thing becomes three. Plan it. |
|
|
121
|
-
| "I can plan in my head" | Plans in your head can't be reviewed or annotated |
|
|
122
|
-
| "This is just a refactor" | Refactors touch more code than features. Plan it. |
|
|
123
|
-
| "I'll write the plan after" | Post-hoc plans are fiction. Plan before. |
|
|
124
|
-
| "I need more context first" | Skills tell you HOW to gather context. Check first. |
|
|
125
|
-
| "The skill is overkill" | Simple things become complex. Use it. |
|
|
126
|
-
| "I know what that skill says" | Skills evolve. Read current version. Invoke it. |
|
|
127
|
-
| "This feels productive" | Undisciplined action wastes time. Skills prevent this. |
|
|
128
|
-
|
|
129
|
-
## Skill Types
|
|
130
|
-
|
|
131
|
-
**Process skills** (spec-brainstorm, spec-plan, spec-implement, spec-finish): Follow exactly.
|
|
132
|
-
Don't adapt away discipline.
|
|
133
|
-
|
|
134
|
-
**Knowledge skills** (oracle-grill-me, oracle-domain-modelling): Adapt principles to
|
|
135
|
-
context. These inform decisions within the workflow.
|
|
136
|
-
|
|
137
|
-
**Discipline skills** (oracle-debug): Strict methodology that must be followed
|
|
138
|
-
exactly — no adaptation that bypasses root-cause investigation.
|
|
139
|
-
|
|
140
|
-
Process skills come first. Knowledge skills get invoked by process skills when needed.
|
|
141
|
-
|
|
142
|
-
## User Instructions
|
|
143
|
-
|
|
144
|
-
"Add X" or "Fix Y" doesn't mean skip workflows. Instructions say WHAT, not HOW.
|
|
145
|
-
The skills define HOW.
|