Fixed the auto sync file watcher and updated setup script to make agent-os default install false
This commit is contained in:
parent
212dda1ce1
commit
c45c2e87a5
7 changed files with 383 additions and 4 deletions
|
|
@ -178,6 +178,9 @@ class GlobalFileWatcher:
|
||||||
watcher = ProjectWatcher(project_id)
|
watcher = ProjectWatcher(project_id)
|
||||||
watcher.start()
|
watcher.start()
|
||||||
self.watchers[project_id] = watcher
|
self.watchers[project_id] = watcher
|
||||||
|
# Enable if we have active watchers
|
||||||
|
if self.watchers:
|
||||||
|
self.enabled = True
|
||||||
|
|
||||||
def stop_project(self, project_id: int):
|
def stop_project(self, project_id: int):
|
||||||
"""Stop watching a project."""
|
"""Stop watching a project."""
|
||||||
|
|
@ -187,6 +190,9 @@ class GlobalFileWatcher:
|
||||||
|
|
||||||
watcher = self.watchers.pop(project_id)
|
watcher = self.watchers.pop(project_id)
|
||||||
watcher.stop()
|
watcher.stop()
|
||||||
|
# Disable if no more watchers
|
||||||
|
if not self.watchers:
|
||||||
|
self.enabled = False
|
||||||
|
|
||||||
def restart_project(self, project_id: int):
|
def restart_project(self, project_id: int):
|
||||||
"""Restart watcher for a project."""
|
"""Restart watcher for a project."""
|
||||||
|
|
|
||||||
BIN
docs/assets/og-image.png
Normal file
BIN
docs/assets/og-image.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 431 KiB |
|
|
@ -5,6 +5,26 @@
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>Claude OS - The AI Operating System That Never Forgets</title>
|
<title>Claude OS - The AI Operating System That Never Forgets</title>
|
||||||
|
|
||||||
|
<!-- Open Graph / Social Media Meta Tags -->
|
||||||
|
<meta property="og:type" content="website">
|
||||||
|
<meta property="og:url" content="https://thebob.dev/claude-os/">
|
||||||
|
<meta property="og:title" content="Claude OS - The AI Operating System That Never Forgets">
|
||||||
|
<meta property="og:description" content="Persistent memory for Claude Code. Index 10,000 files in 3 seconds. 36+ community skills. Never start from zero again.">
|
||||||
|
<meta property="og:image" content="https://thebob.dev/claude-os/assets/og-image.png">
|
||||||
|
<meta property="og:site_name" content="Claude OS">
|
||||||
|
|
||||||
|
<!-- Twitter Card Meta Tags -->
|
||||||
|
<meta name="twitter:card" content="summary_large_image">
|
||||||
|
<meta name="twitter:url" content="https://thebob.dev/claude-os/">
|
||||||
|
<meta name="twitter:title" content="Claude OS - The AI Operating System That Never Forgets">
|
||||||
|
<meta name="twitter:description" content="Persistent memory for Claude Code. Index 10,000 files in 3 seconds. 36+ community skills. Never start from zero again.">
|
||||||
|
<meta name="twitter:image" content="https://thebob.dev/claude-os/assets/og-image.png">
|
||||||
|
|
||||||
|
<!-- General Meta Tags -->
|
||||||
|
<meta name="description" content="Claude OS gives Claude Code persistent memory across sessions. Index 10,000 files in 3 seconds with hybrid indexing. 36+ community skills available.">
|
||||||
|
<meta name="keywords" content="Claude, Claude Code, AI, memory, coding assistant, developer tools, open source">
|
||||||
|
<meta name="author" content="Bob Roberts">
|
||||||
|
|
||||||
<!-- Bootstrap 5 -->
|
<!-- Bootstrap 5 -->
|
||||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3324,6 +3324,35 @@ async def startup_event():
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"❌ Failed to start spec watchers: {e}")
|
logger.error(f"❌ Failed to start spec watchers: {e}")
|
||||||
|
|
||||||
|
# Auto-start file watchers for all projects with hooks enabled
|
||||||
|
try:
|
||||||
|
from app.core.hooks import ProjectHook
|
||||||
|
|
||||||
|
db_manager = get_sqlite_manager()
|
||||||
|
projects = db_manager.list_projects()
|
||||||
|
file_watcher = get_global_watcher()
|
||||||
|
started_count = 0
|
||||||
|
|
||||||
|
for project in projects:
|
||||||
|
try:
|
||||||
|
# Check if project has any enabled hooks
|
||||||
|
hook = ProjectHook(project['id'])
|
||||||
|
hook_status = hook.get_hook_status()
|
||||||
|
|
||||||
|
if hook_status.get('enabled_hooks', 0) > 0:
|
||||||
|
file_watcher.start_project(project['id'])
|
||||||
|
started_count += 1
|
||||||
|
logger.info(f"📂 File watcher started for project {project['name']}")
|
||||||
|
except Exception as e:
|
||||||
|
logger.warning(f"Could not start file watcher for project {project['id']}: {e}")
|
||||||
|
|
||||||
|
if started_count > 0:
|
||||||
|
logger.info(f"✅ File watchers started for {started_count} project(s)")
|
||||||
|
else:
|
||||||
|
logger.info("ℹ️ No projects with hooks enabled - file watchers will start when hooks are configured")
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"❌ Failed to start file watchers: {e}")
|
||||||
|
|
||||||
|
|
||||||
@app.on_event("shutdown")
|
@app.on_event("shutdown")
|
||||||
async def shutdown_event():
|
async def shutdown_event():
|
||||||
|
|
@ -3340,6 +3369,14 @@ async def shutdown_event():
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"❌ Failed to stop spec watchers: {e}")
|
logger.error(f"❌ Failed to stop spec watchers: {e}")
|
||||||
|
|
||||||
|
# Stop all file watchers
|
||||||
|
try:
|
||||||
|
file_watcher = get_global_watcher()
|
||||||
|
file_watcher.stop_all()
|
||||||
|
logger.info("✅ File watchers stopped")
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"❌ Failed to stop file watchers: {e}")
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
"""Start the MCP server."""
|
"""Start the MCP server."""
|
||||||
|
|
|
||||||
|
|
@ -154,7 +154,7 @@ echo ""
|
||||||
# ===== 5. Start RQ Workers (Real-Time Learning System) =====
|
# ===== 5. Start RQ Workers (Real-Time Learning System) =====
|
||||||
echo -e "${YELLOW}5. Starting RQ Workers (Real-Time Learning)...${NC}"
|
echo -e "${YELLOW}5. Starting RQ Workers (Real-Time Learning)...${NC}"
|
||||||
if check_port 6379; then
|
if check_port 6379; then
|
||||||
nohup "$PROJECT_DIR/venv/bin/python3" -m rq worker claude-os:learning claude-os:prompts claude-os:ingest --with-scheduler > "$PROJECT_DIR/logs/rq_workers.log" 2>&1 &
|
nohup "$PROJECT_DIR/venv/bin/rq" worker claude-os:learning claude-os:prompts claude-os:ingest --with-scheduler > "$PROJECT_DIR/logs/rq_workers.log" 2>&1 &
|
||||||
RQ_PID=$!
|
RQ_PID=$!
|
||||||
echo " RQ Workers PID: $RQ_PID (logging to logs/rq_workers.log)"
|
echo " RQ Workers PID: $RQ_PID (logging to logs/rq_workers.log)"
|
||||||
echo -e " ${GREEN}✓ RQ workers started${NC}"
|
echo -e " ${GREEN}✓ RQ workers started${NC}"
|
||||||
|
|
|
||||||
|
|
@ -73,8 +73,8 @@ Let's get your project configured for AI-powered development.
|
||||||
- Default: `http://localhost:8051`
|
- Default: `http://localhost:8051`
|
||||||
- Ask: `Claude OS server URL? [default: http://localhost:8051]`
|
- Ask: `Claude OS server URL? [default: http://localhost:8051]`
|
||||||
|
|
||||||
9. **Agent-OS Setup** (Optional):
|
9. **Agent-OS Setup** (Optional - for advanced users):
|
||||||
- Ask: `Enable Agent-OS for spec-driven development? [Y/n]`
|
- Ask: `Enable Agent-OS for spec-driven development? [y/N]`
|
||||||
- Explain:
|
- Explain:
|
||||||
```
|
```
|
||||||
Agent-OS provides 8 specialized agents for structured feature development:
|
Agent-OS provides 8 specialized agents for structured feature development:
|
||||||
|
|
@ -83,13 +83,14 @@ Let's get your project configured for AI-powered development.
|
||||||
- Generate task breakdowns
|
- Generate task breakdowns
|
||||||
- Implement and verify features
|
- Implement and verify features
|
||||||
|
|
||||||
|
This is recommended for complex projects with formal spec workflows.
|
||||||
Note: Requires Ollama (local) or OpenAI API key for advanced features.
|
Note: Requires Ollama (local) or OpenAI API key for advanced features.
|
||||||
```
|
```
|
||||||
- If YES:
|
- If YES:
|
||||||
- Set `ENABLE_AGENT_OS=true`
|
- Set `ENABLE_AGENT_OS=true`
|
||||||
- Will create `agent-os/` directory structure
|
- Will create `agent-os/` directory structure
|
||||||
- Will symlink agents to `.claude/agents/agent-os/`
|
- Will symlink agents to `.claude/agents/agent-os/`
|
||||||
- If NO:
|
- If NO (default):
|
||||||
- Set `ENABLE_AGENT_OS=false`
|
- Set `ENABLE_AGENT_OS=false`
|
||||||
- Can enable later by manually copying templates
|
- Can enable later by manually copying templates
|
||||||
|
|
||||||
|
|
@ -184,6 +185,18 @@ mkdir -p .claude-os
|
||||||
- Copy from: `{claude_os_dir}/templates/project-files/.claude-os/.gitignore`
|
- Copy from: `{claude_os_dir}/templates/project-files/.claude-os/.gitignore`
|
||||||
- Write to: `./.claude-os/.gitignore`
|
- Write to: `./.claude-os/.gitignore`
|
||||||
|
|
||||||
|
**Install TDD Skill (always - best practice for all projects):**
|
||||||
|
- Create directory: `mkdir -p ./.claude/skills/test-driven-development`
|
||||||
|
- Copy from: `{claude_os_dir}/templates/skills/test-driven-development/SKILL.md`
|
||||||
|
- Write to: `./.claude/skills/test-driven-development/SKILL.md`
|
||||||
|
- Show:
|
||||||
|
```
|
||||||
|
✅ Installed TDD skill (test-driven-development)
|
||||||
|
- Guides RED-GREEN-REFACTOR workflow
|
||||||
|
- Ensures tests fail first, then pass
|
||||||
|
- Use: "I'm using the TDD skill to implement this feature"
|
||||||
|
```
|
||||||
|
|
||||||
**If Agent-OS is enabled (`ENABLE_AGENT_OS=true`):**
|
**If Agent-OS is enabled (`ENABLE_AGENT_OS=true`):**
|
||||||
|
|
||||||
1. **Create agent-os/ directory structure:**
|
1. **Create agent-os/ directory structure:**
|
||||||
|
|
@ -450,6 +463,11 @@ Your project is now connected to Claude OS.
|
||||||
/claude-os-session - Manage development sessions
|
/claude-os-session - Manage development sessions
|
||||||
/claude-os-remember - Quick save to memories
|
/claude-os-remember - Quick save to memories
|
||||||
|
|
||||||
|
🧪 TDD Skill Installed:
|
||||||
|
- RED-GREEN-REFACTOR workflow built-in
|
||||||
|
- Say "I'm using the TDD skill" to activate
|
||||||
|
- Write tests first, watch them fail, then implement
|
||||||
|
|
||||||
📂 Project Structure:
|
📂 Project Structure:
|
||||||
./CLAUDE.md - Project context (auto-loaded every session)
|
./CLAUDE.md - Project context (auto-loaded every session)
|
||||||
./.claude/ - Commands, skills, agents
|
./.claude/ - Commands, skills, agents
|
||||||
|
|
|
||||||
298
templates/skills/test-driven-development/SKILL.md
Normal file
298
templates/skills/test-driven-development/SKILL.md
Normal file
|
|
@ -0,0 +1,298 @@
|
||||||
|
---
|
||||||
|
name: test-driven-development
|
||||||
|
description: Use when implementing any feature or bugfix, before writing implementation code - write the test first, watch it fail, write minimal code to pass; ensures tests actually verify behavior by requiring failure first
|
||||||
|
---
|
||||||
|
|
||||||
|
# Test-Driven Development (TDD)
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
Write the test first. Watch it fail. Write minimal code to pass.
|
||||||
|
|
||||||
|
**Core principle:** If you didn't watch the test fail, you don't know if it tests the right thing.
|
||||||
|
|
||||||
|
**Violating the letter of the rules is violating the spirit of the rules.**
|
||||||
|
|
||||||
|
## When to Use
|
||||||
|
|
||||||
|
**Always:**
|
||||||
|
- New features
|
||||||
|
- Bug fixes
|
||||||
|
- Refactoring
|
||||||
|
- Behavior changes
|
||||||
|
|
||||||
|
**Exceptions (ask your human partner):**
|
||||||
|
- Throwaway prototypes
|
||||||
|
- Generated code
|
||||||
|
- Configuration files
|
||||||
|
|
||||||
|
Thinking "skip TDD just this once"? Stop. That's rationalization.
|
||||||
|
|
||||||
|
## The Iron Law
|
||||||
|
|
||||||
|
```
|
||||||
|
NO PRODUCTION CODE WITHOUT A FAILING TEST FIRST
|
||||||
|
```
|
||||||
|
|
||||||
|
Write code before the test? Delete it. Start over.
|
||||||
|
|
||||||
|
**No exceptions:**
|
||||||
|
- Don't keep it as "reference"
|
||||||
|
- Don't "adapt" it while writing tests
|
||||||
|
- Don't look at it
|
||||||
|
- Delete means delete
|
||||||
|
|
||||||
|
Implement fresh from tests. Period.
|
||||||
|
|
||||||
|
## Red-Green-Refactor
|
||||||
|
|
||||||
|
### RED - Write Failing Test
|
||||||
|
|
||||||
|
Write one minimal test showing what should happen.
|
||||||
|
|
||||||
|
**Good:**
|
||||||
|
```typescript
|
||||||
|
test('retries failed operations 3 times', async () => {
|
||||||
|
let attempts = 0;
|
||||||
|
const operation = () => {
|
||||||
|
attempts++;
|
||||||
|
if (attempts < 3) throw new Error('fail');
|
||||||
|
return 'success';
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = await retryOperation(operation);
|
||||||
|
|
||||||
|
expect(result).toBe('success');
|
||||||
|
expect(attempts).toBe(3);
|
||||||
|
});
|
||||||
|
```
|
||||||
|
Clear name, tests real behavior, one thing
|
||||||
|
|
||||||
|
**Bad:**
|
||||||
|
```typescript
|
||||||
|
test('retry works', async () => {
|
||||||
|
const mock = jest.fn()
|
||||||
|
.mockRejectedValueOnce(new Error())
|
||||||
|
.mockRejectedValueOnce(new Error())
|
||||||
|
.mockResolvedValueOnce('success');
|
||||||
|
await retryOperation(mock);
|
||||||
|
expect(mock).toHaveBeenCalledTimes(3);
|
||||||
|
});
|
||||||
|
```
|
||||||
|
Vague name, tests mock not code
|
||||||
|
|
||||||
|
**Requirements:**
|
||||||
|
- One behavior
|
||||||
|
- Clear name
|
||||||
|
- Real code (no mocks unless unavoidable)
|
||||||
|
|
||||||
|
### Verify RED - Watch It Fail
|
||||||
|
|
||||||
|
**MANDATORY. Never skip.**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm test path/to/test.test.ts
|
||||||
|
```
|
||||||
|
|
||||||
|
Confirm:
|
||||||
|
- Test fails (not errors)
|
||||||
|
- Failure message is expected
|
||||||
|
- Fails because feature missing (not typos)
|
||||||
|
|
||||||
|
**Test passes?** You're testing existing behavior. Fix test.
|
||||||
|
|
||||||
|
**Test errors?** Fix error, re-run until it fails correctly.
|
||||||
|
|
||||||
|
### GREEN - Minimal Code
|
||||||
|
|
||||||
|
Write simplest code to pass the test.
|
||||||
|
|
||||||
|
**Good:**
|
||||||
|
```typescript
|
||||||
|
async function retryOperation<T>(fn: () => Promise<T>): Promise<T> {
|
||||||
|
for (let i = 0; i < 3; i++) {
|
||||||
|
try {
|
||||||
|
return await fn();
|
||||||
|
} catch (e) {
|
||||||
|
if (i === 2) throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new Error('unreachable');
|
||||||
|
}
|
||||||
|
```
|
||||||
|
Just enough to pass
|
||||||
|
|
||||||
|
**Bad:**
|
||||||
|
```typescript
|
||||||
|
async function retryOperation<T>(
|
||||||
|
fn: () => Promise<T>,
|
||||||
|
options?: {
|
||||||
|
maxRetries?: number;
|
||||||
|
backoff?: 'linear' | 'exponential';
|
||||||
|
onRetry?: (attempt: number) => void;
|
||||||
|
}
|
||||||
|
): Promise<T> {
|
||||||
|
// YAGNI
|
||||||
|
}
|
||||||
|
```
|
||||||
|
Over-engineered
|
||||||
|
|
||||||
|
Don't add features, refactor other code, or "improve" beyond the test.
|
||||||
|
|
||||||
|
### Verify GREEN - Watch It Pass
|
||||||
|
|
||||||
|
**MANDATORY.**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm test path/to/test.test.ts
|
||||||
|
```
|
||||||
|
|
||||||
|
Confirm:
|
||||||
|
- Test passes
|
||||||
|
- Other tests still pass
|
||||||
|
- Output pristine (no errors, warnings)
|
||||||
|
|
||||||
|
**Test fails?** Fix code, not test.
|
||||||
|
|
||||||
|
**Other tests fail?** Fix now.
|
||||||
|
|
||||||
|
### REFACTOR - Clean Up
|
||||||
|
|
||||||
|
After green only:
|
||||||
|
- Remove duplication
|
||||||
|
- Improve names
|
||||||
|
- Extract helpers
|
||||||
|
|
||||||
|
Keep tests green. Don't add behavior.
|
||||||
|
|
||||||
|
### Repeat
|
||||||
|
|
||||||
|
Next failing test for next feature.
|
||||||
|
|
||||||
|
## Good Tests
|
||||||
|
|
||||||
|
| Quality | Good | Bad |
|
||||||
|
|---------|------|-----|
|
||||||
|
| **Minimal** | One thing. "and" in name? Split it. | `test('validates email and domain and whitespace')` |
|
||||||
|
| **Clear** | Name describes behavior | `test('test1')` |
|
||||||
|
| **Shows intent** | Demonstrates desired API | Obscures what code should do |
|
||||||
|
|
||||||
|
## Why Order Matters
|
||||||
|
|
||||||
|
**"I'll write tests after to verify it works"**
|
||||||
|
|
||||||
|
Tests written after code pass immediately. Passing immediately proves nothing:
|
||||||
|
- Might test wrong thing
|
||||||
|
- Might test implementation, not behavior
|
||||||
|
- Might miss edge cases you forgot
|
||||||
|
- You never saw it catch the bug
|
||||||
|
|
||||||
|
Test-first forces you to see the test fail, proving it actually tests something.
|
||||||
|
|
||||||
|
**"I already manually tested all the edge cases"**
|
||||||
|
|
||||||
|
Manual testing is ad-hoc. You think you tested everything but:
|
||||||
|
- No record of what you tested
|
||||||
|
- Can't re-run when code changes
|
||||||
|
- Easy to forget cases under pressure
|
||||||
|
- "It worked when I tried it" ≠ comprehensive
|
||||||
|
|
||||||
|
Automated tests are systematic. They run the same way every time.
|
||||||
|
|
||||||
|
## Common Rationalizations
|
||||||
|
|
||||||
|
| Excuse | Reality |
|
||||||
|
|--------|---------|
|
||||||
|
| "Too simple to test" | Simple code breaks. Test takes 30 seconds. |
|
||||||
|
| "I'll test after" | Tests passing immediately prove nothing. |
|
||||||
|
| "Already manually tested" | Ad-hoc ≠ systematic. No record, can't re-run. |
|
||||||
|
| "Need to explore first" | Fine. Throw away exploration, start with TDD. |
|
||||||
|
| "Test hard = design unclear" | Listen to test. Hard to test = hard to use. |
|
||||||
|
| "TDD will slow me down" | TDD faster than debugging. Pragmatic = test-first. |
|
||||||
|
|
||||||
|
## Red Flags - STOP and Start Over
|
||||||
|
|
||||||
|
- Code before test
|
||||||
|
- Test after implementation
|
||||||
|
- Test passes immediately
|
||||||
|
- Can't explain why test failed
|
||||||
|
- Tests added "later"
|
||||||
|
- Rationalizing "just this once"
|
||||||
|
|
||||||
|
**All of these mean: Delete code. Start over with TDD.**
|
||||||
|
|
||||||
|
## Example: Bug Fix
|
||||||
|
|
||||||
|
**Bug:** Empty email accepted
|
||||||
|
|
||||||
|
**RED**
|
||||||
|
```typescript
|
||||||
|
test('rejects empty email', async () => {
|
||||||
|
const result = await submitForm({ email: '' });
|
||||||
|
expect(result.error).toBe('Email required');
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
**Verify RED**
|
||||||
|
```bash
|
||||||
|
$ npm test
|
||||||
|
FAIL: expected 'Email required', got undefined
|
||||||
|
```
|
||||||
|
|
||||||
|
**GREEN**
|
||||||
|
```typescript
|
||||||
|
function submitForm(data: FormData) {
|
||||||
|
if (!data.email?.trim()) {
|
||||||
|
return { error: 'Email required' };
|
||||||
|
}
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Verify GREEN**
|
||||||
|
```bash
|
||||||
|
$ npm test
|
||||||
|
PASS
|
||||||
|
```
|
||||||
|
|
||||||
|
**REFACTOR**
|
||||||
|
Extract validation for multiple fields if needed.
|
||||||
|
|
||||||
|
## Verification Checklist
|
||||||
|
|
||||||
|
Before marking work complete:
|
||||||
|
|
||||||
|
- [ ] Every new function/method has a test
|
||||||
|
- [ ] Watched each test fail before implementing
|
||||||
|
- [ ] Each test failed for expected reason (feature missing, not typo)
|
||||||
|
- [ ] Wrote minimal code to pass each test
|
||||||
|
- [ ] All tests pass
|
||||||
|
- [ ] Output pristine (no errors, warnings)
|
||||||
|
- [ ] Tests use real code (mocks only if unavoidable)
|
||||||
|
- [ ] Edge cases and errors covered
|
||||||
|
|
||||||
|
Can't check all boxes? You skipped TDD. Start over.
|
||||||
|
|
||||||
|
## When Stuck
|
||||||
|
|
||||||
|
| Problem | Solution |
|
||||||
|
|---------|----------|
|
||||||
|
| Don't know how to test | Write wished-for API. Write assertion first. Ask your human partner. |
|
||||||
|
| Test too complicated | Design too complicated. Simplify interface. |
|
||||||
|
| Must mock everything | Code too coupled. Use dependency injection. |
|
||||||
|
| Test setup huge | Extract helpers. Still complex? Simplify design. |
|
||||||
|
|
||||||
|
## Debugging Integration
|
||||||
|
|
||||||
|
Bug found? Write failing test reproducing it. Follow TDD cycle. Test proves fix and prevents regression.
|
||||||
|
|
||||||
|
Never fix bugs without a test.
|
||||||
|
|
||||||
|
## Final Rule
|
||||||
|
|
||||||
|
```
|
||||||
|
Production code → test exists and failed first
|
||||||
|
Otherwise → not TDD
|
||||||
|
```
|
||||||
|
|
||||||
|
No exceptions without your human partner's permission.
|
||||||
Loading…
Add table
Reference in a new issue