ruvnet-kb-first 5.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/LICENSE +21 -0
- package/README.md +674 -0
- package/SKILL.md +740 -0
- package/bin/kb-first.js +123 -0
- package/install/init-project.sh +435 -0
- package/install/install-global.sh +257 -0
- package/install/kb-first-autodetect.sh +108 -0
- package/install/kb-first-command.md +80 -0
- package/install/kb-first-skill.md +262 -0
- package/package.json +87 -0
- package/phases/00-assessment.md +529 -0
- package/phases/01-storage.md +194 -0
- package/phases/01.5-hooks-setup.md +521 -0
- package/phases/02-kb-creation.md +413 -0
- package/phases/03-persistence.md +125 -0
- package/phases/04-visualization.md +170 -0
- package/phases/05-integration.md +114 -0
- package/phases/06-scaffold.md +130 -0
- package/phases/07-build.md +493 -0
- package/phases/08-verification.md +597 -0
- package/phases/09-security.md +512 -0
- package/phases/10-documentation.md +613 -0
- package/phases/11-deployment.md +670 -0
- package/phases/testing.md +713 -0
- package/scripts/1.5-hooks-verify.sh +252 -0
- package/scripts/8.1-code-scan.sh +58 -0
- package/scripts/8.2-import-check.sh +42 -0
- package/scripts/8.3-source-returns.sh +52 -0
- package/scripts/8.4-startup-verify.sh +65 -0
- package/scripts/8.5-fallback-check.sh +63 -0
- package/scripts/8.6-attribution.sh +56 -0
- package/scripts/8.7-confidence.sh +56 -0
- package/scripts/8.8-gap-logging.sh +70 -0
- package/scripts/9-security-audit.sh +202 -0
- package/scripts/init-project.sh +395 -0
- package/scripts/verify-enforcement.sh +167 -0
- package/src/commands/hooks.js +361 -0
- package/src/commands/init.js +315 -0
- package/src/commands/phase.js +372 -0
- package/src/commands/score.js +380 -0
- package/src/commands/status.js +193 -0
- package/src/commands/verify.js +286 -0
- package/src/index.js +56 -0
- package/src/mcp-server.js +412 -0
- package/templates/attention-router.ts +534 -0
- package/templates/code-analysis.ts +683 -0
- package/templates/federated-kb-learner.ts +649 -0
- package/templates/gnn-engine.ts +1091 -0
- package/templates/intentions.md +277 -0
- package/templates/kb-client.ts +905 -0
- package/templates/schema.sql +303 -0
- package/templates/sona-config.ts +312 -0
|
@@ -0,0 +1,493 @@
|
|
|
1
|
+
# Phase 7: Application Build (KB Enforced)
|
|
2
|
+
|
|
3
|
+
## Purpose
|
|
4
|
+
|
|
5
|
+
Build the application with **strict KB enforcement**. No hardcoded domain logic. No shortcuts. Every piece of domain knowledge comes from the KB.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## ⚠️ Critical Warning
|
|
10
|
+
|
|
11
|
+
**This is where shortcuts happen.**
|
|
12
|
+
|
|
13
|
+
Common failures:
|
|
14
|
+
- "I'll just hardcode this one value..."
|
|
15
|
+
- "The KB doesn't have this, so I'll use a default..."
|
|
16
|
+
- "This is faster than querying the KB..."
|
|
17
|
+
|
|
18
|
+
**Every one of these breaks the KB-First principle.**
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## KB Enforcement Rules
|
|
23
|
+
|
|
24
|
+
These rules are **non-negotiable**. Generate `KB_ENFORCEMENT.md` and keep it in context throughout development.
|
|
25
|
+
|
|
26
|
+
```markdown
|
|
27
|
+
# KB ENFORCEMENT RULES
|
|
28
|
+
|
|
29
|
+
## Rule 1: No Hardcoded Domain Logic
|
|
30
|
+
|
|
31
|
+
❌ WRONG:
|
|
32
|
+
```typescript
|
|
33
|
+
const withdrawalRate = 0.04;
|
|
34
|
+
const retirementAge = 65;
|
|
35
|
+
const inflationRate = 0.03;
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
✅ CORRECT:
|
|
39
|
+
```typescript
|
|
40
|
+
const withdrawalRate = await kb.search("safe withdrawal rate");
|
|
41
|
+
const retirementAge = await kb.search("standard retirement age");
|
|
42
|
+
const inflationRate = await kb.search("expected inflation rate");
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Rule 2: Every Domain Function Queries KB
|
|
46
|
+
|
|
47
|
+
Every file in `src/domain/` MUST:
|
|
48
|
+
- Import from `../kb`
|
|
49
|
+
- Query KB for domain knowledge
|
|
50
|
+
- Include kbSources in return
|
|
51
|
+
|
|
52
|
+
❌ WRONG:
|
|
53
|
+
```typescript
|
|
54
|
+
// src/domain/retirement.ts
|
|
55
|
+
export function calculateWithdrawal(portfolio: number) {
|
|
56
|
+
return portfolio * 0.04; // Where did 0.04 come from?
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
✅ CORRECT:
|
|
61
|
+
```typescript
|
|
62
|
+
// src/domain/retirement.ts
|
|
63
|
+
import { kb } from '../kb';
|
|
64
|
+
|
|
65
|
+
export async function calculateWithdrawal(portfolio: number) {
|
|
66
|
+
const rateResult = await kb.search("safe withdrawal rate");
|
|
67
|
+
return {
|
|
68
|
+
amount: portfolio * rateResult.value,
|
|
69
|
+
kbSources: rateResult.sources
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Rule 3: All Responses Include kbSources
|
|
75
|
+
|
|
76
|
+
Every function that returns domain knowledge MUST include the sources.
|
|
77
|
+
|
|
78
|
+
```typescript
|
|
79
|
+
interface DomainResponse<T> {
|
|
80
|
+
data: T;
|
|
81
|
+
kbSources: {
|
|
82
|
+
nodeId: string;
|
|
83
|
+
expert: string;
|
|
84
|
+
confidence: number;
|
|
85
|
+
url: string;
|
|
86
|
+
}[];
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Rule 4: Startup Verification Required
|
|
91
|
+
|
|
92
|
+
The application MUST verify KB connection before doing anything else.
|
|
93
|
+
|
|
94
|
+
```typescript
|
|
95
|
+
// src/index.ts - FIRST LINE OF main()
|
|
96
|
+
async function main() {
|
|
97
|
+
const kbReady = await kb.verifyConnection();
|
|
98
|
+
if (!kbReady) {
|
|
99
|
+
console.error("KB unavailable. Exiting.");
|
|
100
|
+
process.exit(1);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Now initialize app
|
|
104
|
+
initializeApp();
|
|
105
|
+
}
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## Rule 5: No Fallback Logic
|
|
109
|
+
|
|
110
|
+
The KB is the source of truth. If it's unavailable, the app should fail, not use defaults.
|
|
111
|
+
|
|
112
|
+
❌ WRONG:
|
|
113
|
+
```typescript
|
|
114
|
+
const rules = await kb.getRules() || DEFAULT_RULES;
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
✅ CORRECT:
|
|
118
|
+
```typescript
|
|
119
|
+
const rules = await kb.getRules();
|
|
120
|
+
if (!rules) {
|
|
121
|
+
throw new Error("KB rules unavailable");
|
|
122
|
+
}
|
|
123
|
+
```
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
## Build Sequence
|
|
129
|
+
|
|
130
|
+
### 7.1 Generate KB_ENFORCEMENT.md
|
|
131
|
+
|
|
132
|
+
Create the enforcement rules document above and save it to the project root.
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
# This file MUST be in context for all subsequent steps
|
|
136
|
+
cat > KB_ENFORCEMENT.md << 'EOF'
|
|
137
|
+
[contents above]
|
|
138
|
+
EOF
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### 7.2 Plan Domain Functions
|
|
142
|
+
|
|
143
|
+
Before writing any code, list ALL domain functions needed:
|
|
144
|
+
|
|
145
|
+
```markdown
|
|
146
|
+
## Domain Functions Plan
|
|
147
|
+
|
|
148
|
+
### Calculations
|
|
149
|
+
- [ ] calculateWithdrawalRate(portfolio, age, riskTolerance)
|
|
150
|
+
- [ ] calculateSocialSecurityBenefit(birthYear, claimingAge)
|
|
151
|
+
- [ ] calculateRothConversionAmount(income, bracket)
|
|
152
|
+
- [ ] calculateMedicarePremium(income)
|
|
153
|
+
|
|
154
|
+
### Recommendations
|
|
155
|
+
- [ ] recommendClaimingAge(profile)
|
|
156
|
+
- [ ] recommendAssetAllocation(age, risk)
|
|
157
|
+
- [ ] recommendWithdrawalStrategy(situation)
|
|
158
|
+
|
|
159
|
+
### Comparisons
|
|
160
|
+
- [ ] compareScenarios(scenarioA, scenarioB)
|
|
161
|
+
- [ ] compareStrategies(strategies[])
|
|
162
|
+
|
|
163
|
+
### Validations
|
|
164
|
+
- [ ] validateProfile(profile)
|
|
165
|
+
- [ ] validateScenario(scenario)
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### 7.3 Implement Domain Functions (One at a Time)
|
|
169
|
+
|
|
170
|
+
**Implement ONE function at a time. Verify before moving to the next.**
|
|
171
|
+
|
|
172
|
+
For each function:
|
|
173
|
+
|
|
174
|
+
1. **Write the function** importing from kb/
|
|
175
|
+
2. **Verify immediately:**
|
|
176
|
+
```bash
|
|
177
|
+
# Check: Does it import from kb?
|
|
178
|
+
grep "from.*kb" src/domain/[file].ts
|
|
179
|
+
|
|
180
|
+
# Check: Does it return kbSources?
|
|
181
|
+
grep "kbSources" src/domain/[file].ts
|
|
182
|
+
|
|
183
|
+
# Check: Any hardcoded values?
|
|
184
|
+
grep -E "[0-9]+\.[0-9]+" src/domain/[file].ts # Decimals
|
|
185
|
+
grep -E "= [0-9]+" src/domain/[file].ts # Integers
|
|
186
|
+
```
|
|
187
|
+
3. **If verification fails** → Fix before continuing
|
|
188
|
+
4. **If verification passes** → Move to next function
|
|
189
|
+
|
|
190
|
+
### 7.4 Implement API Layer
|
|
191
|
+
|
|
192
|
+
API routes should:
|
|
193
|
+
- Call domain functions (not KB directly)
|
|
194
|
+
- Pass through kbSources
|
|
195
|
+
- Handle errors appropriately
|
|
196
|
+
|
|
197
|
+
```typescript
|
|
198
|
+
// src/api/routes/retirement.ts
|
|
199
|
+
import { calculateWithdrawal } from '../../domain/retirement';
|
|
200
|
+
|
|
201
|
+
router.post('/calculate-withdrawal', async (req, res) => {
|
|
202
|
+
try {
|
|
203
|
+
const result = await calculateWithdrawal(req.body.portfolio);
|
|
204
|
+
res.json({
|
|
205
|
+
withdrawal: result.data,
|
|
206
|
+
sources: result.kbSources // Always include sources
|
|
207
|
+
});
|
|
208
|
+
} catch (error) {
|
|
209
|
+
res.status(500).json({ error: 'Calculation failed', kbSources: [] });
|
|
210
|
+
}
|
|
211
|
+
});
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
### 7.5 Implement Entry Point
|
|
215
|
+
|
|
216
|
+
The entry point MUST verify KB first:
|
|
217
|
+
|
|
218
|
+
```typescript
|
|
219
|
+
// src/index.ts
|
|
220
|
+
import { kb } from './kb';
|
|
221
|
+
import { initializeApp } from './app';
|
|
222
|
+
|
|
223
|
+
async function main() {
|
|
224
|
+
console.log('Verifying KB connection...');
|
|
225
|
+
|
|
226
|
+
// FIRST: Verify KB
|
|
227
|
+
const kbHealth = await kb.verifyConnection();
|
|
228
|
+
if (!kbHealth.healthy) {
|
|
229
|
+
console.error('KB unavailable:', kbHealth.error);
|
|
230
|
+
process.exit(1);
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
console.log(`KB ready: ${kbHealth.nodeCount} nodes`);
|
|
234
|
+
|
|
235
|
+
// THEN: Initialize app
|
|
236
|
+
await initializeApp();
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
main().catch((error) => {
|
|
240
|
+
console.error('Startup failed:', error);
|
|
241
|
+
process.exit(1);
|
|
242
|
+
});
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
### 7.6 Implement UI
|
|
246
|
+
|
|
247
|
+
UI components should:
|
|
248
|
+
- Display kbSources for transparency
|
|
249
|
+
- Show confidence levels
|
|
250
|
+
- Handle loading states for KB queries
|
|
251
|
+
|
|
252
|
+
```tsx
|
|
253
|
+
function WithdrawalResult({ result }) {
|
|
254
|
+
return (
|
|
255
|
+
<div>
|
|
256
|
+
<h2>Recommended Withdrawal: ${result.withdrawal}</h2>
|
|
257
|
+
|
|
258
|
+
{/* Always show sources */}
|
|
259
|
+
<div className="sources">
|
|
260
|
+
<h4>Based on:</h4>
|
|
261
|
+
{result.sources.map(source => (
|
|
262
|
+
<div key={source.nodeId}>
|
|
263
|
+
<span className="expert">{source.expert}</span>
|
|
264
|
+
<span className="confidence">
|
|
265
|
+
{(source.confidence * 100).toFixed(0)}% confidence
|
|
266
|
+
</span>
|
|
267
|
+
<a href={source.url}>Source</a>
|
|
268
|
+
</div>
|
|
269
|
+
))}
|
|
270
|
+
</div>
|
|
271
|
+
</div>
|
|
272
|
+
);
|
|
273
|
+
}
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
### 7.7 Integration Testing
|
|
277
|
+
|
|
278
|
+
Test the complete flow:
|
|
279
|
+
|
|
280
|
+
```typescript
|
|
281
|
+
describe('KB Enforcement', () => {
|
|
282
|
+
test('all responses include kbSources', async () => {
|
|
283
|
+
const result = await api.post('/calculate-withdrawal', { portfolio: 1000000 });
|
|
284
|
+
expect(result.sources).toBeDefined();
|
|
285
|
+
expect(result.sources.length).toBeGreaterThan(0);
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
test('app fails without KB', async () => {
|
|
289
|
+
// Disconnect KB
|
|
290
|
+
await kb.disconnect();
|
|
291
|
+
|
|
292
|
+
// App should fail to start
|
|
293
|
+
await expect(startApp()).rejects.toThrow();
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
test('no hardcoded values in domain/', async () => {
|
|
297
|
+
const domainFiles = await glob('src/domain/**/*.ts');
|
|
298
|
+
for (const file of domainFiles) {
|
|
299
|
+
const content = await fs.readFile(file, 'utf-8');
|
|
300
|
+
// Check for suspicious patterns
|
|
301
|
+
expect(content).not.toMatch(/= 0\.\d+/); // Hardcoded decimals
|
|
302
|
+
expect(content).not.toMatch(/DEFAULT_/); // Default constants
|
|
303
|
+
}
|
|
304
|
+
});
|
|
305
|
+
});
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
---
|
|
309
|
+
|
|
310
|
+
## Incremental Verification Scripts
|
|
311
|
+
|
|
312
|
+
Run these after each step:
|
|
313
|
+
|
|
314
|
+
### verify-domain.sh
|
|
315
|
+
```bash
|
|
316
|
+
#!/bin/bash
|
|
317
|
+
echo "Verifying domain functions..."
|
|
318
|
+
|
|
319
|
+
errors=0
|
|
320
|
+
|
|
321
|
+
# Check all domain files import from kb
|
|
322
|
+
for file in src/domain/*.ts; do
|
|
323
|
+
if ! grep -q "from.*kb" "$file"; then
|
|
324
|
+
echo "❌ $file does not import from kb/"
|
|
325
|
+
errors=$((errors + 1))
|
|
326
|
+
fi
|
|
327
|
+
done
|
|
328
|
+
|
|
329
|
+
# Check all domain files return kbSources
|
|
330
|
+
for file in src/domain/*.ts; do
|
|
331
|
+
if ! grep -q "kbSources" "$file"; then
|
|
332
|
+
echo "❌ $file does not include kbSources"
|
|
333
|
+
errors=$((errors + 1))
|
|
334
|
+
fi
|
|
335
|
+
done
|
|
336
|
+
|
|
337
|
+
# Check for hardcoded values
|
|
338
|
+
for file in src/domain/*.ts; do
|
|
339
|
+
if grep -E "= 0\.[0-9]+" "$file" | grep -v "confidence"; then
|
|
340
|
+
echo "⚠️ $file may have hardcoded decimal values"
|
|
341
|
+
fi
|
|
342
|
+
done
|
|
343
|
+
|
|
344
|
+
if [ $errors -eq 0 ]; then
|
|
345
|
+
echo "✅ Domain verification passed"
|
|
346
|
+
else
|
|
347
|
+
echo "❌ $errors errors found"
|
|
348
|
+
exit 1
|
|
349
|
+
fi
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
### verify-entry.sh
|
|
353
|
+
```bash
|
|
354
|
+
#!/bin/bash
|
|
355
|
+
echo "Verifying entry point..."
|
|
356
|
+
|
|
357
|
+
# Check verifyConnection is called first
|
|
358
|
+
if ! head -20 src/index.ts | grep -q "verifyConnection"; then
|
|
359
|
+
echo "❌ Entry point does not verify KB connection first"
|
|
360
|
+
exit 1
|
|
361
|
+
fi
|
|
362
|
+
|
|
363
|
+
# Check process.exit on failure
|
|
364
|
+
if ! grep -q "process.exit(1)" src/index.ts; then
|
|
365
|
+
echo "❌ Entry point does not exit on KB failure"
|
|
366
|
+
exit 1
|
|
367
|
+
fi
|
|
368
|
+
|
|
369
|
+
echo "✅ Entry point verification passed"
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
---
|
|
373
|
+
|
|
374
|
+
## Intelligence Layer Integration
|
|
375
|
+
|
|
376
|
+
### For Decision Web (GNN) Applications
|
|
377
|
+
|
|
378
|
+
```typescript
|
|
379
|
+
// src/domain/simulation.ts
|
|
380
|
+
import { kb } from '../kb';
|
|
381
|
+
import { gnn } from '../intelligence/gnn';
|
|
382
|
+
|
|
383
|
+
export async function simulateDecision(change: DecisionChange) {
|
|
384
|
+
// Get the decision graph from KB
|
|
385
|
+
const graph = await kb.getDecisionGraph();
|
|
386
|
+
|
|
387
|
+
// Use GNN to simulate cascade
|
|
388
|
+
const simulation = await gnn.simulate(graph, change);
|
|
389
|
+
|
|
390
|
+
return {
|
|
391
|
+
data: simulation,
|
|
392
|
+
kbSources: graph.sources
|
|
393
|
+
};
|
|
394
|
+
}
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
### For Routing (Attention) Applications
|
|
398
|
+
|
|
399
|
+
```typescript
|
|
400
|
+
// src/domain/query.ts
|
|
401
|
+
import { kb } from '../kb';
|
|
402
|
+
import { attention } from '../intelligence/attention';
|
|
403
|
+
|
|
404
|
+
export async function processQuery(query: string) {
|
|
405
|
+
// Route to appropriate expert domain
|
|
406
|
+
const expert = await attention.routeToExpert(query);
|
|
407
|
+
|
|
408
|
+
// Search within that domain
|
|
409
|
+
const results = await kb.search(query, { namespace: expert.domain });
|
|
410
|
+
|
|
411
|
+
return {
|
|
412
|
+
data: results,
|
|
413
|
+
kbSources: results.sources,
|
|
414
|
+
routedTo: expert.name
|
|
415
|
+
};
|
|
416
|
+
}
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
### For Learning (SONA) Applications
|
|
420
|
+
|
|
421
|
+
```typescript
|
|
422
|
+
// src/domain/recommendation.ts
|
|
423
|
+
import { kb } from '../kb';
|
|
424
|
+
import { sona } from '../intelligence/sona';
|
|
425
|
+
|
|
426
|
+
export async function getRecommendation(profile: UserProfile) {
|
|
427
|
+
// Find similar successful patterns
|
|
428
|
+
const patterns = await sona.recallPatterns(profile);
|
|
429
|
+
|
|
430
|
+
// Get supporting KB content
|
|
431
|
+
const kbContent = await kb.search(patterns[0].query);
|
|
432
|
+
|
|
433
|
+
return {
|
|
434
|
+
data: {
|
|
435
|
+
recommendation: patterns[0].recommendation,
|
|
436
|
+
basedOn: patterns.map(p => p.summary),
|
|
437
|
+
confidence: patterns[0].confidence
|
|
438
|
+
},
|
|
439
|
+
kbSources: kbContent.sources
|
|
440
|
+
};
|
|
441
|
+
}
|
|
442
|
+
```
|
|
443
|
+
|
|
444
|
+
---
|
|
445
|
+
|
|
446
|
+
## Quality Gate Checklist
|
|
447
|
+
|
|
448
|
+
Before proceeding to Phase 8:
|
|
449
|
+
|
|
450
|
+
```
|
|
451
|
+
[ ] KB_ENFORCEMENT.md in project root
|
|
452
|
+
[ ] All domain functions listed and implemented
|
|
453
|
+
[ ] Each function verified (imports kb, returns kbSources)
|
|
454
|
+
[ ] No hardcoded domain values
|
|
455
|
+
[ ] Entry point verifies KB first
|
|
456
|
+
[ ] Entry point exits if KB unavailable
|
|
457
|
+
[ ] API routes pass through kbSources
|
|
458
|
+
[ ] UI displays sources and confidence
|
|
459
|
+
[ ] Integration tests pass
|
|
460
|
+
[ ] Intelligence layer properly integrated (if applicable)
|
|
461
|
+
```
|
|
462
|
+
|
|
463
|
+
---
|
|
464
|
+
|
|
465
|
+
## Common Mistakes to Avoid
|
|
466
|
+
|
|
467
|
+
### 1. "Just this one constant"
|
|
468
|
+
❌ `const MAX_AGE = 100;`
|
|
469
|
+
✅ Query KB for age limits
|
|
470
|
+
|
|
471
|
+
### 2. "Default fallback"
|
|
472
|
+
❌ `const rate = kb.get() || 0.04;`
|
|
473
|
+
✅ Fail if KB unavailable
|
|
474
|
+
|
|
475
|
+
### 3. "Caching without source tracking"
|
|
476
|
+
❌ Cache value, lose source
|
|
477
|
+
✅ Cache entire response including sources
|
|
478
|
+
|
|
479
|
+
### 4. "Lazy loading gone wrong"
|
|
480
|
+
❌ Initialize app, then check KB
|
|
481
|
+
✅ Check KB first, then initialize
|
|
482
|
+
|
|
483
|
+
### 5. "UI showing results without sources"
|
|
484
|
+
❌ "Your withdrawal: $40,000"
|
|
485
|
+
✅ "Your withdrawal: $40,000 (based on Bengen 1994, 95% confidence)"
|
|
486
|
+
|
|
487
|
+
---
|
|
488
|
+
|
|
489
|
+
## Exit Criteria
|
|
490
|
+
|
|
491
|
+
All domain logic comes from KB. All responses have sources. No shortcuts.
|
|
492
|
+
|
|
493
|
+
**Proceed to Phase 8: Final Verification**
|