Roo-Code/PHASE_4_INTEGRATION_GUIDE.md

398 lines
12 KiB
Markdown

# Phase 4 Integration Guide: Wiring Concurrency & Lessons
This guide covers integrating ConcurrencyGuard and append_lesson_to_claude into the tool dispatcher for full Phase 4 functionality.
## Current State Summary
- **ConcurrencyGuard**: ✅ Implemented and tested (16 tests passing)
- **append_lesson_to_claude**: ✅ Implemented and tested (16 tests passing)
- **write_to_file schema**: ✅ Updated with read_hash parameter
- **Tool registration**: ✅ append_lesson_to_claude registered
**What's missing**: Integration into tool dispatcher execution flow
## Integration Architecture
```
Tool Execution Flow (Target)
1. read_file() called
├─ Get file content
└─ recordSnapshot(filePath, content, turnId, intentId)
└─ Persisted to .orchestration/concurrency_snapshots.jsonl
2. Agent processes file (can happen in parallel with other agents)
3. write_to_file(path, content, intent_id, mutation_class, read_hash) called
├─ Pre-hook: verifyBeforeWrite(path)
│ ├─ If snapshot exists: compare hashes
│ ├─ If STALE_FILE error: return and block write
│ └─ If OK: proceed with write
├─ Execute: fs.writeFileSync(path, content)
└─ Post-hook: clearSnapshot(path)
4. Verification fails (lint/test)
└─ append_lesson_to_claude(lesson_text)
└─ Write to CLAUDE.md with timestamp
```
## Implementation: Phase 4a - ConcurrencyGuard in read_file
### Location: Tool dispatcher for read_file
```typescript
// In the tool executor for read_file:
import { ConcurrencyGuard } from "@/core/intent/ConcurrencyGuard"
import { v4 as uuidv4 } from "uuid" // or use existing turnId
const concurrencyGuard = new ConcurrencyGuard()
const currentTurnId = messageInfo.id.turnId || uuidv4() // Unique per agent turn
const currentIntentId = intentHookEngine.getCurrentSessionIntent()
// After successfully reading file:
const fileContent = fs.readFileSync(filePath, "utf8")
concurrencyGuard.recordSnapshot(
filePath,
fileContent,
currentTurnId,
currentIntentId // optional
)
return {
content: fileContent,
note: "File snapshot recorded for concurrency control"
}
```
### Integration Point Example
In `src/core/prompts/tools/native-tools/read_file.ts` (or dispatcher):
```typescript
// Add imports
import { ConcurrencyGuard } from "@/core/intent/ConcurrencyGuard"
// Create guard instance (singleton or per-turn)
let concurrencyGuard: ConcurrencyGuard
function initializeGuard() {
if (!concurrencyGuard) {
concurrencyGuard = new ConcurrencyGuard()
}
return concurrencyGuard
}
// In read file handler:
export async function readFile(params: ReadFileParams) {
const filePath = params.path
const content = fs.readFileSync(filePath, "utf8")
// Record snapshot for later concurrency verification
const guard = initializeGuard()
guard.recordSnapshot(
filePath,
content,
params.turnId || "default-turn",
params.intentId // from current session
)
return { content }
}
```
## Implementation: Phase 4b - Verify Before Write
### Location: write_to_file tool handler pre-execution
```typescript
// In write_to_file handler (before fs.writeFileSync):
import { ConcurrencyGuard } from "@/core/intent/ConcurrencyGuard"
const concurrencyGuard = new ConcurrencyGuard()
function executeWriteToFile(params: WriteFileParams): void {
const filePath = params.path
const content = params.content
// Phase 4: Check for stale file before write
const error = concurrencyGuard.verifyBeforeWrite(filePath)
if (error) {
// STALE_FILE error detected
return {
error: true,
type: error.type,
message: error.message,
details: {
file_path: error.file_path,
expected_hash: error.expected_hash,
current_hash: error.current_hash,
},
resolution: error.resolution, // "Please re-read the file using read_file..."
}
}
// Write is safe, proceed
fs.mkdirSync(path.dirname(filePath), { recursive: true })
fs.writeFileSync(filePath, content, "utf8")
// Phase 3: Log to trace
const traceLogger = new TraceLogger()
traceLogger.logTrace(
params.intent_id,
filePath,
content,
params.mutation_class,
messageInfo.id.requestId
)
// Phase 4: Clear snapshot after successful write
concurrencyGuard.clearSnapshot(filePath)
return { success: true, path: filePath }
}
```
## Implementation: Phase 4c - Append Lesson on Verification Failure
### Location: Verification handler (lint/test executor)
```typescript
// In verification step handler (e.g., lint, test runner):
import { appendLessonToClaude } from "@/core/tools/append_lesson_to_claude"
async function runLintVerification(filePath: string) {
try {
const result = await execLint(filePath)
if (!result.success) {
// Lint failed, record lesson
const lessonText = `**Context**: Verification step: Lint check on ${path.basename(filePath)}
**Failure**: ESLint warnings exceeded threshold:
${result.violations.map((v) => `- ${v.rule}: ${v.message}`).join("\n")}
**Resolution**: ${result.suggestedFix || "Review and fix linting violations"}`
const lessonResult = await appendLessonToClaude(lessonText)
console.log(`Lesson recorded: ${lessonResult.message}`)
return {
success: false,
message: result.message,
lesson_recorded: true,
lesson_path: lessonResult.path,
}
}
return { success: true }
} catch (err) {
// Handle unexpected errors
const lessonText = `**Context**: Verification step: Lint execution failed on ${filePath}
**Failure**: ${err instanceof Error ? err.message : String(err)}
**Resolution**: Check ESLint configuration and file permissions`
await appendLessonToClaude(lessonText)
throw err
}
}
```
### Verification Context Examples
```typescript
// Type check failure
async function runTypeChecker(files: string[]) {
try {
return await execTypescript(files)
} catch (err) {
const lessonText = `**Context**: TypeScript compilation on ${files.length} files
**Failure**: ${err.message}
**Resolution**: Add proper type definitions to function parameters and return types`
await appendLessonToClaude(lessonText)
throw err
}
}
// Test failure
async function runTests() {
const result = await execVitest()
if (result.failed > 0) {
const lessonText = `**Context**: Vitest suite (${result.total} tests)
**Failure**: ${result.failed} tests failed:
${result.failures.map((f) => `- ${f.test}: ${f.error}`).join("\n")}
**Resolution**: Fix failing tests and verify all assertions pass`
await appendLessonToClaude(lessonText)
}
return result
}
```
## Integration Checklist
- [ ] **Step 1: Import ConcurrencyGuard in tool dispatcher**
- [ ] Add import statement
- [ ] Create singleton or per-turn instance
- [ ] Test initialization
- [ ] **Step 2: Hook recordSnapshot into read_file**
- [ ] After file content retrieved
- [ ] Pass turnId and intentId
- [ ] Test snapshot creation in .orchestration dir
- [ ] **Step 3: Hook verifyBeforeWrite into write_to_file**
- [ ] Extract read_hash from tool params
- [ ] Call verifyBeforeWrite before fs.writeFileSync
- [ ] Return STALE_FILE error on conflict
- [ ] Test conflict detection with manual file modification
- [ ] **Step 4: Hook clearSnapshot after successful write**
- [ ] Call clearSnapshot(path) post-write
- [ ] Test snapshot cleanup via getSnapshot returning undefined
- [ ] **Step 5: Integrate TraceLogger post-hook (Phase 3)**
- [ ] Call traceLogger.logTrace after write success
- [ ] Use mutation_class from tool params
- [ ] Test trace entries in agent_trace.jsonl
- [ ] **Step 6: Integrate append_lesson_to_claude**
- [ ] Hook into lint verification handler
- [ ] Hook into test verification handler
- [ ] Hook into type check handler
- [ ] Test lesson creation in CLAUDE.md
- [ ] **Step 7: Test end-to-end flow**
- [ ] Agent A reads file → snapshot
- [ ] Agent B reads file → snapshot
- [ ] Agent A writes file → success, snapshot cleared
- [ ] Agent B tries write → STALE_FILE error
- [ ] Agent B re-reads → new snapshot
- [ ] Agent B writes → success
- [ ] **Step 8: Test failure lesson recording**
- [ ] Run verification that fails
- [ ] Check CLAUDE.md for new entry
- [ ] Verify timestamp and context recorded
## Minimal Implementation (Quick Win)
If full integration is complex, start with:
```typescript
// 1. In write_to_file handler only:
const guard = new ConcurrencyGuard()
const error = guard.verifyBeforeWrite(filePath)
if (error) return error
// 2. In linter handler:
if (lintFailed) {
await appendLessonToClaude(`**Context**: Lint failed\n**Failure**: ${msg}\n**Resolution**: Fix violations`)
}
```
This provides core concurrency safety + lesson recording with minimal changes.
## Testing Integration
After wiring, verify:
```bash
# Test 1: Snapshot recording
git checkout tmp-file.ts # Create a tracked file
echo "test" > tmp-file.ts
node -e "
const { ConcurrencyGuard } = require('./src/core/intent/ConcurrencyGuard');
const guard = new ConcurrencyGuard();
guard.recordSnapshot('tmp-file.ts', 'test', 'test-turn');
console.log('Snapshot:', guard.getSnapshot('tmp-file.ts'));
"
# Expected: Snapshot object with read_hash, turn_id, timestamp
# Test 2: Stale file detection
echo "modified" > tmp-file.ts
node -e "
const { ConcurrencyGuard } = require('./src/core/intent/ConcurrencyGuard');
const guard = new ConcurrencyGuard();
guard.recordSnapshot('tmp-file.ts', 'test', 'test-turn');
const error = guard.verifyBeforeWrite('tmp-file.ts');
console.log('Error:', error?.type); // Should be 'STALE_FILE'
"
# Test 3: Lesson recording
node -e "
const { appendLessonToClaude } = require('./src/core/tools/append_lesson_to_claude');
appendLessonToClaude('**Context**: Test lesson\n**Failure**: Demo\n**Resolution**: Works!').then(r => console.log(r));
"
# Expected: success: true, message contains "Lesson recorded"
```
## Performance Targets
After integration, monitor:
| Metric | Target | Notes |
|--------|--------|-------|
| recordSnapshot latency | < 5ms | Per read operation |
| verifyBeforeWrite latency | < 2ms | Per write operation |
| Conflict detection accuracy | 100% | Hash matching |
| lesson append latency | < 10ms | Per failure |
| Snapshot log size | < 1MB per 1k operations | JSONL compression |
## Troubleshooting
### Issue: "Cannot find module ConcurrencyGuard"
- **Fix**: Ensure import path is correct: `@/core/intent/ConcurrencyGuard`
- **Check**: File exists at `src/core/intent/ConcurrencyGuard.ts`
### Issue: "Snapshot not persisting"
- **Fix**: Ensure `.orchestration` directory is writable
- **Check**: `fs.existsSync(".orchestration")` returns true after recordSnapshot
### Issue: "STALE_FILE error not being returned"
- **Fix**: Verify read_hash is being passed to write_to_file
- **Check**: Tool params include read_hash field
### Issue: "CLAUDE.md not being created"
- **Fix**: Ensure current working directory is writable
- **Check**: `fs.existsSync("CLAUDE.md")` after appendLessonToClaude
## Rollback Plan
If issues arise:
1. **Disable concurrency checks** (optional):
```typescript
// In verifyBeforeWrite pre-hook:
if (FEATURE_FLAG_DISABLE_CONCURRENCY_CHECKS) {
return null // Skip verification
}
```
2. **Disable lesson recording**:
```typescript
// In verification handler:
if (FEATURE_FLAG_DISABLE_LESSON_RECORDING) {
return {success: !result.failed} // Skip lesson append
}
```
3. **Archive logs**:
- Backup `.orchestration/concurrency_snapshots.jsonl`
- Backup `CLAUDE.md`
## Future Enhancements
- [ ] Async snapshot recording for high concurrency
- [ ] Batch snapshot writes (max 100 per flush)
- [ ] Distributed snapshot store (cloud backup)
- [ ] Dashboard visualization of conflicts
- [ ] Auto-parsing of verification output
- [ ] Lesson similarity clustering
- [ ] Agent activity timeline