@oleksandr.rudnychenko/sync_loop 0.3.2 → 0.3.3
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/dist/src/init.js +21 -0
- package/dist/src/init.js.map +1 -1
- package/dist/src/template/.agent-loop/patterns/api-standards.md +15 -64
- package/dist/src/template/.agent-loop/patterns/code-patterns.md +31 -199
- package/dist/src/template/.agent-loop/patterns/refactoring-workflow.md +34 -61
- package/dist/src/template/.agent-loop/patterns/testing-guide.md +49 -162
- package/dist/src/template/.agent-loop/reasoning-kernel.md +68 -15
- package/dist/src/template/.agent-loop/validate-n.md +3 -39
- package/dist/src/template/AGENTS.md +33 -4
- package/dist/src/template/backlog-index.md +28 -0
- package/dist/src/template/wiring/agents-claude-architect.md +89 -0
- package/dist/src/template/wiring/agents-claude-fixer.md +45 -0
- package/dist/src/template/wiring/agents-claude.md +14 -2
- package/dist/src/template/wiring/agents-github-architect.md +94 -0
- package/dist/src/template/wiring/agents-github-fixer.md +53 -0
- package/dist/src/template/wiring/agents-github.md +14 -2
- package/dist/src/template/wiring/skills-diagnose-failure.md +34 -0
- package/package.json +15 -3
- package/src/template/.agent-loop/patterns/api-standards.md +15 -64
- package/src/template/.agent-loop/patterns/code-patterns.md +31 -199
- package/src/template/.agent-loop/patterns/refactoring-workflow.md +34 -61
- package/src/template/.agent-loop/patterns/testing-guide.md +49 -162
- package/src/template/.agent-loop/reasoning-kernel.md +68 -15
- package/src/template/.agent-loop/validate-n.md +3 -39
- package/src/template/AGENTS.md +33 -4
- package/src/template/backlog-index.md +28 -0
- package/src/template/wiring/agents-claude-architect.md +89 -0
- package/src/template/wiring/agents-claude-fixer.md +45 -0
- package/src/template/wiring/agents-claude.md +14 -2
- package/src/template/wiring/agents-github-architect.md +94 -0
- package/src/template/wiring/agents-github-fixer.md +53 -0
- package/src/template/wiring/agents-github.md +14 -2
- package/src/template/wiring/skills-diagnose-failure.md +34 -0
|
@@ -7,55 +7,39 @@ Referenced from [../patterns.md](../patterns.md).
|
|
|
7
7
|
|
|
8
8
|
## Refactoring Checklist
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
☐ Create report in docs/reports/ if the refactor is major
|
|
34
|
-
```
|
|
10
|
+
**Phase 1: PLAN**
|
|
11
|
+
- Identify all files to move, rename, or extract
|
|
12
|
+
- Map old imports to new imports
|
|
13
|
+
- Check for documentation references (README, docstrings, agent-loop specs)
|
|
14
|
+
- Identify public interfaces that must remain stable
|
|
15
|
+
|
|
16
|
+
**Phase 2: EXECUTE**
|
|
17
|
+
- Move files to their new locations
|
|
18
|
+
- Update imports in moved files (internal relative references)
|
|
19
|
+
- Update all caller imports (search the entire codebase for every reference)
|
|
20
|
+
- Update documentation examples if they contain import paths
|
|
21
|
+
- Update `.agent-loop/patterns.md` structure section if layout changed
|
|
22
|
+
|
|
23
|
+
**Phase 3: VALIDATE (NON-NEGOTIABLE)**
|
|
24
|
+
1. Type check: run the project type checker
|
|
25
|
+
2. Run tests: execute the test suite with fail-fast
|
|
26
|
+
3. Check docs: search for old import paths across all files
|
|
27
|
+
4. Verify no orphaned imports (unused or broken)
|
|
28
|
+
|
|
29
|
+
**Phase 4: DOCUMENT**
|
|
30
|
+
- Update README structure section
|
|
31
|
+
- Update architecture docs if needed
|
|
32
|
+
- Create report in `docs/reports/` if the refactor is major
|
|
35
33
|
|
|
36
34
|
---
|
|
37
35
|
|
|
38
36
|
## Example: Moving a Module File
|
|
39
37
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
# e.g., relative imports that changed due to new directory depth
|
|
46
|
-
|
|
47
|
-
# 3. Find ALL references to the old path
|
|
48
|
-
grep -r "from src.modules.old_location.processor" .
|
|
49
|
-
grep -r "import old_location.processor" .
|
|
50
|
-
|
|
51
|
-
# 4. Update each reference found:
|
|
52
|
-
# - tests/unit/test_processor.py
|
|
53
|
-
# - src/modules/new_location/tasks.py
|
|
54
|
-
# - docs/architecture.md (if it mentions import paths)
|
|
55
|
-
|
|
56
|
-
# 5. MANDATORY: Run validation
|
|
57
|
-
# Type check → Tests → Grep for leftover old paths
|
|
58
|
-
```
|
|
38
|
+
1. Move the file from its old location to the new location
|
|
39
|
+
2. Update imports inside the moved file (relative references that changed due to new directory depth)
|
|
40
|
+
3. Search the entire codebase for all references to the old path — tests, other modules, and documentation
|
|
41
|
+
4. Update each reference found to point to the new path
|
|
42
|
+
5. Run the mandatory validation: type check → tests → search for leftover old paths
|
|
59
43
|
|
|
60
44
|
**Why tests after docs?** Documentation often contains import examples. Tests verify imports actually work and catch typos in updated paths.
|
|
61
45
|
|
|
@@ -63,23 +47,12 @@ grep -r "import old_location.processor" .
|
|
|
63
47
|
|
|
64
48
|
## Example: Extracting a Function to a New Module
|
|
65
49
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
# 3. In the original file, replace the function body with an import:
|
|
74
|
-
# from src.libs.parsing.helpers import parse_response
|
|
75
|
-
|
|
76
|
-
# 4. Find all OTHER callers of the original location
|
|
77
|
-
grep -r "from src.modules.analysis.utils import parse_response" .
|
|
78
|
-
|
|
79
|
-
# 5. Update all callers to use the new import path
|
|
80
|
-
|
|
81
|
-
# 6. VALIDATE: type check + tests + grep for old path
|
|
82
|
-
```
|
|
50
|
+
1. Create the new module file
|
|
51
|
+
2. Move the function definition to the new file and update its internal imports
|
|
52
|
+
3. In the original file, replace the function body with a re-export from the new location
|
|
53
|
+
4. Search for all other callers of the function at the original location
|
|
54
|
+
5. Update all callers to use the new import path
|
|
55
|
+
6. Run the mandatory validation: type check → tests → search for old path
|
|
83
56
|
|
|
84
57
|
---
|
|
85
58
|
|
|
@@ -7,187 +7,84 @@ Referenced from [../patterns.md](../patterns.md).
|
|
|
7
7
|
|
|
8
8
|
## Test Organization
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
10
|
+
Organize tests into a top-level `tests/` directory with clear separation:
|
|
11
|
+
|
|
12
|
+
| Directory | Purpose |
|
|
13
|
+
|-----------|---------|
|
|
14
|
+
| `tests/conftest` or `tests/helpers` | Shared fixtures, global setup |
|
|
15
|
+
| `tests/factories` | Test data builders |
|
|
16
|
+
| `tests/mocks` | Mock implementations for external dependencies |
|
|
17
|
+
| `tests/api/` | API/endpoint tests (HTTP client) |
|
|
18
|
+
| `tests/integration/` | Multi-component workflow tests |
|
|
19
|
+
| `tests/unit/` | Pure logic tests (no I/O) |
|
|
19
20
|
|
|
20
21
|
---
|
|
21
22
|
|
|
22
23
|
## Pattern 1: Fixture-Based Setup
|
|
23
24
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
yield
|
|
32
|
-
app.context._context = None
|
|
33
|
-
|
|
34
|
-
# Test app configuration
|
|
35
|
-
@pytest.fixture
|
|
36
|
-
def test_app(monkeypatch: pytest.MonkeyPatch, tmp_path: Path):
|
|
37
|
-
"""Configure app with test-safe environment."""
|
|
38
|
-
monkeypatch.setenv("APP_ENV", "testing")
|
|
39
|
-
monkeypatch.setenv("ENABLE_BACKGROUND_TASKS", "0")
|
|
40
|
-
yield create_app()
|
|
41
|
-
|
|
42
|
-
# API client for endpoint tests
|
|
43
|
-
@pytest.fixture
|
|
44
|
-
def client(test_app):
|
|
45
|
-
return TestClient(test_app)
|
|
46
|
-
```
|
|
25
|
+
Define reusable **fixtures** (setup/teardown helpers) that isolate test state:
|
|
26
|
+
|
|
27
|
+
- **Environment isolation fixture**: resets any module-level singletons or global state before and after each test. Ensures one test cannot leak state into another.
|
|
28
|
+
- **Test app fixture**: configures the application with test-safe environment variables (e.g., test database URL, disabled background tasks) and yields a configured app instance.
|
|
29
|
+
- **Client fixture**: wraps the test app in an HTTP test client for endpoint-level tests.
|
|
30
|
+
|
|
31
|
+
Each fixture is scoped to the narrowest lifecycle needed — per-test for state resets, per-session for expensive resources like database connections.
|
|
47
32
|
|
|
48
33
|
---
|
|
49
34
|
|
|
50
35
|
## Pattern 2: Factory Pattern for Test Data
|
|
51
36
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
def create(
|
|
56
|
-
id: str | None = None,
|
|
57
|
-
name: str = "Test Entity",
|
|
58
|
-
entity_type: str = "default",
|
|
59
|
-
**extras: Any,
|
|
60
|
-
) -> dict[str, Any]:
|
|
61
|
-
return {
|
|
62
|
-
"id": id or str(uuid4()),
|
|
63
|
-
"name": name,
|
|
64
|
-
"metadata": {"type": entity_type, **extras},
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
@staticmethod
|
|
68
|
-
def with_full_analysis() -> dict[str, Any]:
|
|
69
|
-
"""Semantic constructor for entity with all analysis fields populated."""
|
|
70
|
-
return EntityFactory.create(
|
|
71
|
-
name="Fully Analyzed Entity",
|
|
72
|
-
entity_type="analyzed",
|
|
73
|
-
score=85.0,
|
|
74
|
-
grade="B",
|
|
75
|
-
)
|
|
76
|
-
```
|
|
37
|
+
Create a **factory class** (or set of builder functions) that produces valid test entities with sensible defaults. Each factory method accepts optional overrides via keyword arguments so tests only specify the fields relevant to the scenario.
|
|
38
|
+
|
|
39
|
+
Provide **semantic constructors** — named factory methods like `with_full_analysis()` or `as_admin_user()` — that configure the entity for a specific test scenario. This makes test setup self-documenting and avoids duplicated setup logic across test files.
|
|
77
40
|
|
|
78
41
|
---
|
|
79
42
|
|
|
80
43
|
## Pattern 3: Mock External Dependencies
|
|
81
44
|
|
|
82
|
-
|
|
83
|
-
class MockExternalService:
|
|
84
|
-
"""Mock for any external service boundary (LLM, API, storage)."""
|
|
85
|
-
def __init__(self, response: dict | str | None = None):
|
|
86
|
-
self.response = response or self._default_response()
|
|
87
|
-
self.calls: list[dict] = []
|
|
88
|
-
|
|
89
|
-
async def __call__(self, prompt: str, context: str, **kwargs):
|
|
90
|
-
self.calls.append({"prompt": prompt, "context": context})
|
|
91
|
-
return json.dumps(self.response), {}
|
|
92
|
-
|
|
93
|
-
@property
|
|
94
|
-
def call_count(self) -> int:
|
|
95
|
-
return len(self.calls)
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
Usage:
|
|
99
|
-
```python
|
|
100
|
-
@pytest.fixture
|
|
101
|
-
def mock_service() -> MockExternalService:
|
|
102
|
-
return MockExternalService(response={"score": 85})
|
|
103
|
-
|
|
104
|
-
def test_analysis_delegates_to_service(mock_service):
|
|
105
|
-
service = AnalysisService(external=mock_service)
|
|
106
|
-
result = service.analyze(...)
|
|
107
|
-
assert mock_service.call_count == 1
|
|
108
|
-
```
|
|
45
|
+
Define a **mock class** for each external boundary (LLM, HTTP API, storage backend, message queue). The mock:
|
|
109
46
|
|
|
110
|
-
|
|
47
|
+
- Accepts a configurable response via its constructor
|
|
48
|
+
- Records every call (arguments, timestamps) in an internal list
|
|
49
|
+
- Returns the configured response on each invocation
|
|
50
|
+
- Exposes a `call_count` property for verification
|
|
111
51
|
|
|
112
|
-
|
|
52
|
+
Tests inject the mock via fixture, replacing the real dependency. After the test action, assertions verify both the result and the mock's call history.
|
|
113
53
|
|
|
114
|
-
|
|
115
|
-
class TestParseResponse:
|
|
116
|
-
def test_valid_json_response(self):
|
|
117
|
-
response = '{"entity_type": "analyzed", "score": 85}'
|
|
118
|
-
result = parse_response(response)
|
|
119
|
-
assert result.entity_type == EntityType.ANALYZED
|
|
54
|
+
---
|
|
120
55
|
|
|
121
|
-
|
|
122
|
-
result = parse_response("Not JSON")
|
|
123
|
-
assert result.entity_type == EntityType.UNKNOWN
|
|
56
|
+
## Pattern 4: Class-Based Test Organization
|
|
124
57
|
|
|
125
|
-
|
|
126
|
-
result = parse_response('{"entity_type": "analyzed"}')
|
|
127
|
-
assert result.score == 0.0
|
|
128
|
-
```
|
|
58
|
+
Group related test cases into a **test class** named after the unit under test (e.g., `TestParseResponse`, `TestOrderService`). Each method within the class tests one behavior: happy path, error path, edge case, or default behavior. The class name provides namespace grouping in test runner output.
|
|
129
59
|
|
|
130
60
|
---
|
|
131
61
|
|
|
132
62
|
## Pattern 5: Parametrized Tests
|
|
133
63
|
|
|
134
|
-
|
|
135
|
-
@pytest.mark.parametrize("score,expected_grade", [
|
|
136
|
-
(95, "A"), (90, "A"),
|
|
137
|
-
(89.9, "B"), (85, "B"), (80, "B"),
|
|
138
|
-
(79, "C"), (70, "C"),
|
|
139
|
-
(69, "D"), (60, "D"),
|
|
140
|
-
(59, "F"), (0, "F"),
|
|
141
|
-
])
|
|
142
|
-
def test_grade_thresholds(score: float, expected_grade: str):
|
|
143
|
-
assert compute_grade(score) == expected_grade
|
|
144
|
-
```
|
|
64
|
+
Use the test framework's **parametrize** mechanism to run one test function across multiple input/output pairs. Define the parameter sets as a list of tuples — each tuple contains the input values and the expected outcome. This eliminates repetitive test methods for boundary-value or threshold logic.
|
|
145
65
|
|
|
146
66
|
---
|
|
147
67
|
|
|
148
68
|
## Pattern 6: Three-Layer Test Strategy
|
|
149
69
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
# INTEGRATION: Multiple components, mocked external I/O
|
|
157
|
-
def test_analysis_pipeline(mock_service, mock_repository):
|
|
158
|
-
service = AnalysisService(external=mock_service, repo=mock_repository)
|
|
159
|
-
report = service.analyze(entities=[...])
|
|
160
|
-
assert report.aggregate_score > 0
|
|
161
|
-
|
|
162
|
-
# API: HTTP endpoint, full stack with test client
|
|
163
|
-
def test_analyze_endpoint(client, mock_data):
|
|
164
|
-
response = client.post("/api/v1/analyze", json=mock_data)
|
|
165
|
-
assert response.status_code == 200
|
|
166
|
-
assert "score" in response.json()
|
|
167
|
-
```
|
|
70
|
+
Structure tests into three layers with distinct characteristics:
|
|
71
|
+
|
|
72
|
+
- **Unit tests**: Pure logic, no I/O, no external dependencies. Test a single function or class method in isolation. Fast (< 10ms each).
|
|
73
|
+
- **Integration tests**: Multiple components wired together, external I/O mocked at the boundary. Test that services, repositories, and adapters compose correctly.
|
|
74
|
+
- **API tests**: Full HTTP request/response cycle through a test client. Verify status codes, response shapes, and error envelopes.
|
|
168
75
|
|
|
169
76
|
---
|
|
170
77
|
|
|
171
78
|
## Pattern 7: Assertion Patterns
|
|
172
79
|
|
|
173
|
-
|
|
174
|
-
# ✅ Specific property checks
|
|
175
|
-
assert report.task_id == "task-1"
|
|
176
|
-
assert len(report.metrics) > 0
|
|
177
|
-
assert "total_items" in [m.name for m in report.metrics]
|
|
80
|
+
Write assertions that verify **specific properties**, not just truthiness:
|
|
178
81
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
82
|
+
- Check exact field values on result objects
|
|
83
|
+
- Verify collection lengths and membership
|
|
84
|
+
- Use range/constraint assertions (value within expected bounds, enum membership)
|
|
85
|
+
- Assert on collection-wide properties (all items satisfy a predicate, at least one item matches)
|
|
182
86
|
|
|
183
|
-
|
|
184
|
-
assert all(m.value >= 0 for m in report.metrics)
|
|
185
|
-
assert any(r.entity_type == "analyzed" for r in results)
|
|
186
|
-
|
|
187
|
-
# ❌ Vague — what is being verified?
|
|
188
|
-
assert report
|
|
189
|
-
assert result is not None
|
|
190
|
-
```
|
|
87
|
+
Avoid vague assertions like "result is not None" or bare truthiness checks — they pass on wrong data.
|
|
191
88
|
|
|
192
89
|
---
|
|
193
90
|
|
|
@@ -195,14 +92,13 @@ assert result is not None
|
|
|
195
92
|
|
|
196
93
|
Format: `test_<action>_<condition>_<outcome>`
|
|
197
94
|
|
|
198
|
-
|
|
199
|
-
test_returns_report
|
|
200
|
-
test_metrics_computed_correctly
|
|
201
|
-
test_unknown_type_falls_back_to_default
|
|
202
|
-
test_invalid_json_fallback
|
|
203
|
-
test_missing_fields_use_defaults
|
|
204
|
-
test_empty_input_returns_empty_report
|
|
205
|
-
```
|
|
95
|
+
Examples:
|
|
96
|
+
- `test_returns_report` — basic happy path
|
|
97
|
+
- `test_metrics_computed_correctly` — specific behavior
|
|
98
|
+
- `test_unknown_type_falls_back_to_default` — edge case
|
|
99
|
+
- `test_invalid_json_fallback` — error handling
|
|
100
|
+
- `test_missing_fields_use_defaults` — default behavior
|
|
101
|
+
- `test_empty_input_returns_empty_report` — boundary condition
|
|
206
102
|
|
|
207
103
|
---
|
|
208
104
|
|
|
@@ -237,16 +133,7 @@ test_empty_input_returns_empty_report # Boundary condition
|
|
|
237
133
|
2. **Adjacent modules second** — run tests for callers/consumers
|
|
238
134
|
3. **Full suite last** — once local confidence is high, run everything
|
|
239
135
|
|
|
240
|
-
|
|
241
|
-
# Targeted
|
|
242
|
-
pytest tests/unit/test_processor.py -x -v
|
|
243
|
-
|
|
244
|
-
# Adjacent
|
|
245
|
-
pytest tests/unit/ tests/integration/ -x -v -k "processor or analysis"
|
|
246
|
-
|
|
247
|
-
# Full suite
|
|
248
|
-
pytest tests/ -x -v
|
|
249
|
-
```
|
|
136
|
+
Use the project's test runner with verbose and fail-fast flags. Filter by keyword or path to target specific modules during iterative development.
|
|
250
137
|
|
|
251
138
|
---
|
|
252
139
|
|
|
@@ -312,20 +312,39 @@ LEARN:
|
|
|
312
312
|
|
|
313
313
|
### 7. REPORT (Session Log)
|
|
314
314
|
|
|
315
|
-
|
|
315
|
+
The REPORT stage produces exactly one of three outcomes: a **report**, a **backlog task**, or **nothing**.
|
|
316
|
+
Apply the decision tree below — follow it top to bottom, take the first matching branch.
|
|
316
317
|
|
|
317
|
-
|
|
318
|
+
#### Decision Tree: Report vs Backlog vs Skip
|
|
318
319
|
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
320
|
+
```
|
|
321
|
+
Was work implemented and committed this session?
|
|
322
|
+
│
|
|
323
|
+
├─ YES → Did the work touch multiple files or change architecture/patterns?
|
|
324
|
+
│ │
|
|
325
|
+
│ ├─ YES → Write REPORT to docs/reports/
|
|
326
|
+
│ │ (multi-file refactor, new feature, root-cause fix,
|
|
327
|
+
│ │ architecture change, pattern change)
|
|
328
|
+
│ │
|
|
329
|
+
│ └─ NO → SKIP (single-file edit, cosmetic fix, docs-only update)
|
|
330
|
+
│
|
|
331
|
+
└─ NO → Was an investigation or plan produced without implementation?
|
|
332
|
+
│
|
|
333
|
+
├─ YES → Write BACKLOG TASK to docs/backlog/
|
|
334
|
+
│ (needs approval, complex decomposition required,
|
|
335
|
+
│ lower priority than current sprint, blocked on dependency)
|
|
336
|
+
│
|
|
337
|
+
└─ NO → SKIP (question answered, context gathered, trivial lookup)
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
**Key distinction:** Reports document **completed work**. Backlog tasks document **planned but unexecuted work**.
|
|
341
|
+
Never create both for the same task. If you implemented the work, write a report. If you only planned it, write a backlog task.
|
|
342
|
+
|
|
343
|
+
#### Report: Completed Work
|
|
344
|
+
|
|
345
|
+
**Trigger:** Implementation was done this session AND touched ≥2 files or changed architecture/patterns.
|
|
327
346
|
|
|
328
|
-
**
|
|
347
|
+
**Structure:**
|
|
329
348
|
|
|
330
349
|
```markdown
|
|
331
350
|
# {Short Description}
|
|
@@ -355,10 +374,44 @@ After completing a non-trivial task, persist a session summary to `docs/reports/
|
|
|
355
374
|
{What was persisted to patterns.md / patterns/ specs / glossary}
|
|
356
375
|
```
|
|
357
376
|
|
|
358
|
-
**File
|
|
359
|
-
|
|
360
|
-
|
|
377
|
+
**File:** `docs/reports/YYYY-MM-DD-{slug}.md`
|
|
378
|
+
**Artifacts:** `docs/reports/artifacts/`
|
|
379
|
+
|
|
380
|
+
#### Backlog Task: Planned but Deferred Work
|
|
381
|
+
|
|
382
|
+
**Trigger:** Investigation or planning was done this session BUT implementation was NOT executed.
|
|
383
|
+
Reasons to defer: needs approval, requires decomposition, lower priority, blocked on external dependency.
|
|
384
|
+
|
|
385
|
+
**Structure:**
|
|
386
|
+
|
|
387
|
+
```markdown
|
|
388
|
+
# {Task Title}
|
|
389
|
+
|
|
390
|
+
**Date:** YYYY-MM-DD
|
|
391
|
+
**Priority:** P0–P3
|
|
392
|
+
**State:** planned
|
|
393
|
+
|
|
394
|
+
## Context
|
|
395
|
+
{Why this task exists — what was investigated, what triggered it}
|
|
396
|
+
|
|
397
|
+
## Action Plan
|
|
398
|
+
{Step-by-step implementation plan with file paths and scope}
|
|
399
|
+
|
|
400
|
+
## Acceptance Criteria
|
|
401
|
+
{Concrete conditions that define "done" — gate results, test coverage, behavior}
|
|
402
|
+
|
|
403
|
+
## Dependencies
|
|
404
|
+
{What must be resolved before this can start — other tasks, approvals, external}
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
**File:** `docs/backlog/YYYY-MM-DD-{slug}.md`
|
|
408
|
+
**Index:** After creating the task file, add a row to `docs/backlog/index.md` with task number, title, priority (P0–P3), state (`planned`), date, and filename.
|
|
409
|
+
|
|
410
|
+
#### Common Rules
|
|
411
|
+
|
|
361
412
|
- Naming: date-prefixed, lowercase-kebab-case, no `_v1`/`_new` suffixes
|
|
413
|
+
- Never create both a report and a backlog task for the same piece of work
|
|
414
|
+
- If a backlog task is later implemented, mark it `done` in the index and write a report for the implementation session
|
|
362
415
|
|
|
363
416
|
---
|
|
364
417
|
|
|
@@ -460,7 +513,7 @@ LEARN
|
|
|
460
513
|
[one-line do-more/do-less heuristic]
|
|
461
514
|
|
|
462
515
|
REPORT (if non-trivial)
|
|
463
|
-
[docs/reports/YYYY-MM-DD-{slug}.md
|
|
516
|
+
[docs/reports/YYYY-MM-DD-{slug}.md | docs/backlog/YYYY-MM-DD-{slug}.md — or "skipped (trivial)"]
|
|
464
517
|
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
465
518
|
```
|
|
466
519
|
|
|
@@ -53,51 +53,15 @@ When modifying any of these, check all neighbors in the coupling path.
|
|
|
53
53
|
|
|
54
54
|
### Shapes
|
|
55
55
|
|
|
56
|
-
The **signature contract** of a function, method, or class:
|
|
57
|
-
|
|
58
|
-
```python
|
|
59
|
-
# Shape = name + parameters + return type + raises
|
|
60
|
-
def query(
|
|
61
|
-
self,
|
|
62
|
-
collection: str,
|
|
63
|
-
query_text: str,
|
|
64
|
-
*,
|
|
65
|
-
filters: dict | None = None,
|
|
66
|
-
limit: int = 10,
|
|
67
|
-
) -> list[Result]:
|
|
68
|
-
...
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
A shape change is anything that alters the call contract:
|
|
72
|
-
adding/removing parameters, changing types, or modifying return types.
|
|
56
|
+
The **signature contract** of a function, method, or class: its name, parameter names and types (including keyword-only and optional parameters), return type, and declared exceptions. A shape change is anything that alters the call contract: adding or removing parameters, changing parameter or return types, or modifying exception declarations.
|
|
73
57
|
|
|
74
58
|
### Boundaries
|
|
75
59
|
|
|
76
|
-
The **module interface** —
|
|
77
|
-
|
|
78
|
-
```python
|
|
79
|
-
# module/__init__.py
|
|
80
|
-
from .service import MyService # Public boundary
|
|
81
|
-
from .routes import router # Public boundary
|
|
82
|
-
|
|
83
|
-
# Private (not exported) — can change freely
|
|
84
|
-
# from .internal import _helper
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
Boundary changes affect every consumer that imports from the module.
|
|
60
|
+
The **module interface** — the set of symbols explicitly exported as public. Public exports are the symbols listed in the module's index file or namespace declaration. Everything not exported is private and can change freely. Boundary changes affect every consumer that imports from the module.
|
|
88
61
|
|
|
89
62
|
### Bridges
|
|
90
63
|
|
|
91
|
-
The **contracts between modules** — how
|
|
92
|
-
|
|
93
|
-
```python
|
|
94
|
-
# Bridge: module_a → module_b
|
|
95
|
-
# Contract: ServiceA.process() returns list[Result]
|
|
96
|
-
# Consumer: ServiceB expects this shape
|
|
97
|
-
|
|
98
|
-
# If ServiceA.process() changes return type:
|
|
99
|
-
# → ServiceB breaks (bridge violation)
|
|
100
|
-
```
|
|
64
|
+
The **contracts between modules** — how one module's output becomes another module's input. A bridge connects a producer (the function or service returning data) to a consumer (the function or service expecting that data). If the producer changes the shape of its output, the consumer breaks unless it is also updated.
|
|
101
65
|
|
|
102
66
|
---
|
|
103
67
|
|
package/src/template/AGENTS.md
CHANGED
|
@@ -147,11 +147,40 @@ If uncertain, choose isolated and reversible changes.
|
|
|
147
147
|
|
|
148
148
|
---
|
|
149
149
|
|
|
150
|
-
## 9. Reporting & Artifacts
|
|
150
|
+
## 9. Reporting, Backlog & Artifacts
|
|
151
151
|
|
|
152
|
-
|
|
152
|
+
The REPORT stage (stage 7) produces exactly one of three outcomes per task:
|
|
153
|
+
|
|
154
|
+
```
|
|
155
|
+
Work implemented this session?
|
|
156
|
+
├─ YES + multi-file or architecture change → REPORT
|
|
157
|
+
├─ YES + single-file cosmetic/docs-only → SKIP
|
|
158
|
+
├─ NO + investigation/plan produced → BACKLOG TASK
|
|
159
|
+
└─ NO + trivial lookup/question → SKIP
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
**Key rule:** Reports record **completed work**. Backlog tasks record **planned but unexecuted work**. Never create both for the same task.
|
|
163
|
+
|
|
164
|
+
### Reports (completed work)
|
|
165
|
+
|
|
166
|
+
- Path: `docs/reports/YYYY-MM-DD-{slug}.md`
|
|
153
167
|
- Artifacts: `docs/reports/artifacts/`
|
|
154
|
-
-
|
|
168
|
+
- Trigger: implementation was done this session AND touched ≥2 files or changed architecture/patterns
|
|
169
|
+
- Contents: summary, scope, changes, verification results, learned patterns
|
|
170
|
+
|
|
171
|
+
### Backlog (planned but deferred work)
|
|
172
|
+
|
|
173
|
+
- Index: `docs/backlog/index.md` — priority-sorted table with task state
|
|
174
|
+
- Tasks: `docs/backlog/YYYY-MM-DD-{slug}.md` — one file per task
|
|
175
|
+
- Trigger: investigation or planning was done BUT implementation was NOT executed (needs approval, requires decomposition, lower priority, blocked on dependency)
|
|
176
|
+
- Contents: context, Action Plan, acceptance criteria, priority (P0–P3), dependencies
|
|
177
|
+
- After creating a task file, add a row to `docs/backlog/index.md`
|
|
178
|
+
- When a backlog task is later implemented, mark it `done` in the index and write a report for that session
|
|
179
|
+
|
|
180
|
+
### Learning Memory
|
|
181
|
+
|
|
182
|
+
- `.agent-loop/patterns.md` and `.agent-loop/patterns/*.md`
|
|
183
|
+
- Updated during LEARN (stage 6), independent of report/backlog routing
|
|
155
184
|
|
|
156
|
-
|
|
185
|
+
Full decision tree and templates: see [reasoning-kernel.md § REPORT](.agent-loop/reasoning-kernel.md).
|
|
157
186
|
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Backlog
|
|
2
|
+
|
|
3
|
+
Planned tasks awaiting implementation. Each task is a separate file in this folder.
|
|
4
|
+
|
|
5
|
+
## Priority Levels
|
|
6
|
+
|
|
7
|
+
| Priority | Meaning |
|
|
8
|
+
|----------|---------|
|
|
9
|
+
| **P0 — Critical** | Blocking issue or regression. Must be resolved before any other work. |
|
|
10
|
+
| **P1 — High** | Important feature or fix. Next in queue after critical items. |
|
|
11
|
+
| **P2 — Normal** | Standard work item. Implement when bandwidth allows. |
|
|
12
|
+
| **P3 — Low** | Nice-to-have improvement. Defer until higher-priority items clear. |
|
|
13
|
+
|
|
14
|
+
## Task States
|
|
15
|
+
|
|
16
|
+
| State | Meaning |
|
|
17
|
+
|-------|---------|
|
|
18
|
+
| `planned` | Investigated and planned. Action Plan written. Ready to implement. |
|
|
19
|
+
| `in-progress` | Currently being worked on. |
|
|
20
|
+
| `blocked` | Cannot proceed — dependency or question unresolved. |
|
|
21
|
+
| `done` | Implemented and validated. Keep for reference, then archive. |
|
|
22
|
+
|
|
23
|
+
## Index
|
|
24
|
+
|
|
25
|
+
<!-- Add rows as tasks are created. Keep sorted by priority then date. -->
|
|
26
|
+
|
|
27
|
+
| # | Task | Priority | State | Created | File |
|
|
28
|
+
|---|------|----------|-------|---------|------|
|