mirror of
https://github.com/proffesor-for-testing/agentic-qe.git
synced 2026-09-19 08:45:47 +08:00
669e1e1d9f
Rename the QCSD "Grooming" phase to "Refinement" in all TypeScript types, YAML hooks, agent definitions, architecture docs, and catalogs. This aligns with modern Scrum terminology (backlog refinement vs grooming). - Update QCSDPhase type literal: 'grooming' → 'refinement' - Rename hook identifiers: pre-grooming-* → pre-refinement-* - Update cross-phase feedback loop names (Loops 2 & 4) - Update agent cross_phase_memory sections - Update MCP server phase enums - Update architecture docs, catalogs, demos, and changelog Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
23 KiB
23 KiB
Cross-Phase Memory Implementation
Version: 1.2 Date: 2026-01-25 Status: ✅ IMPLEMENTED & INTEGRATED
Implementation Status
| Component | Status | Location |
|---|---|---|
| TypeScript Types | ✅ Implemented | v3/src/types/cross-phase-signals.ts |
| Memory Service | ✅ Implemented | v3/src/memory/cross-phase-memory.ts |
| Hook Executor | ✅ Implemented | v3/src/hooks/cross-phase-hooks.ts |
| Hook Config | ✅ Implemented | .claude/hooks/cross-phase-memory.yaml |
| MCP Handlers | ✅ INTEGRATED | v3/src/mcp/handlers/cross-phase-handlers.ts |
| MCP Server | ✅ INTEGRATED | v3/src/mcp/server.ts (8 new tools) |
| Integration Tests | ✅ 11 PASSING | v3/tests/integration/cross-phase-integration.test.ts |
Commits
50dc1aaa- feat(v3): implement cross-phase memory system for QCSD feedback loops54e90176- feat(v3): integrate cross-phase memory with MCP server + add tests
MCP Tools Available
| Tool | Description |
|---|---|
mcp__agentic_qe__cross_phase_store |
Store signals by loop type |
mcp__agentic_qe__cross_phase_query |
Query signals with filters |
mcp__agentic_qe__agent_complete |
Trigger hooks on agent completion |
mcp__agentic_qe__phase_start |
Get injected signals at phase start |
mcp__agentic_qe__phase_end |
Store accumulated signals at phase end |
mcp__agentic_qe__cross_phase_stats |
Get memory statistics |
mcp__agentic_qe__format_signals |
Format for agent prompt injection |
mcp__agentic_qe__cross_phase_cleanup |
Clean up expired signals |
Overview
This document defines the persistent memory architecture that enables automated cross-phase feedback loops in QCSD. Without this memory layer, feedback loops are manual; with it, they become automated.
Note: The schemas and configurations below are now actual TypeScript code - see Implementation Status table above.
Memory Architecture
Namespace Structure
qcsd-memory/
├── production-patterns/ # Loop 1 & 2: Production → Earlier phases
│ ├── defect-weights/ # Risk weights from defect analysis
│ ├── failure-modes/ # Common failure patterns
│ └── sla-violations/ # Performance/reliability issues
│
├── development-patterns/ # Loop 4: Development → Refinement
│ ├── coverage-gaps/ # Untestable code patterns
│ ├── ac-problems/ # Requirements that caused issues
│ └── test-debt/ # Technical debt indicators
│
├── cicd-patterns/ # Loop 3: CI/CD → Development
│ ├── flaky-tests/ # Flaky test patterns
│ ├── gate-failures/ # Quality gate failure reasons
│ └── build-health/ # Build stability metrics
│
└── cross-phase-signals/ # Routing signals between phases
├── ideation-inputs/ # What Ideation should know
├── refinement-inputs/ # What Refinement should know
└── development-inputs/ # What Development should know
Loop 1: Production → Ideation (Strategic)
Memory Schema
interface ProductionRiskSignal {
id: string; // "risk-signal-2026-Q1-001"
timestamp: string; // ISO 8601
source: "production";
target: "ideation";
loopType: "strategic";
riskWeights: {
category: string; // "payment-integration", "auth-session"
weight: number; // 0.0 - 1.0 (higher = riskier)
confidence: number; // 0.0 - 1.0
evidence: {
defectCount: number;
percentageOfTotal: number;
severityDistribution: Record<string, number>;
timeRange: { start: string; end: string };
};
}[];
recommendations: {
forRiskAssessor: string[]; // ["Weight payment risks at 0.85"]
forQualityCriteria: string[]; // ["Security category = P0 for payment features"]
};
expiresAt: string; // When this signal becomes stale
}
Storage Implementation
// PRODUCTION PHASE: Store risk signals after analyzing defects
// Step 1: Analyze production defects
const defectAnalysis = await mcp__agentic_qe__defect_predict({
target: "production-logs/",
timeRange: "last-90-days"
});
// Step 2: Extract risk weights
const riskWeights = extractRiskWeights(defectAnalysis);
// Step 3: Store for Ideation consumption
await mcp__agentic_qe__memory_store({
key: `risk-signal-${quarter}-${Date.now()}`,
namespace: "qcsd-memory/production-patterns/defect-weights",
value: {
id: `risk-signal-${quarter}-${Date.now()}`,
timestamp: new Date().toISOString(),
source: "production",
target: "ideation",
loopType: "strategic",
riskWeights: [
{
category: "payment-integration",
weight: 0.85,
confidence: 0.92,
evidence: {
defectCount: 47,
percentageOfTotal: 47,
severityDistribution: { P1: 12, P2: 23, P3: 12 },
timeRange: { start: "2025-10-01", end: "2026-01-01" }
}
},
{
category: "auth-session",
weight: 0.70,
confidence: 0.88,
evidence: {
defectCount: 23,
percentageOfTotal: 23,
severityDistribution: { P1: 5, P2: 10, P3: 8 },
timeRange: { start: "2025-10-01", end: "2026-01-01" }
}
}
],
recommendations: {
forRiskAssessor: [
"Weight payment-integration risks at 0.85 (HIGH)",
"Weight auth-session risks at 0.70 (HIGH)",
"Require timeout/retry strategy for payment features"
],
forQualityCriteria: [
"Security category = P0 for features touching payments",
"Reliability category = P0 for session management"
]
},
expiresAt: new Date(Date.now() + 90 * 24 * 60 * 60 * 1000).toISOString()
}
});
// Step 4: Notify learning coordinator
await mcp__agentic_qe__memory_share({
sourceAgentId: "qe-defect-predictor",
targetAgentIds: ["qe-learning-coordinator"],
knowledgeDomain: "production-risk-signals"
});
Retrieval Implementation (Ideation Phase)
// IDEATION PHASE: Query risk signals before risk assessment
// Step 1: Query production signals
const productionSignals = await mcp__agentic_qe__memory_query({
pattern: "risk-signal-*",
namespace: "qcsd-memory/production-patterns/defect-weights"
});
// Step 2: Filter to non-expired signals
const activeSignals = productionSignals.filter(
s => new Date(s.expiresAt) > new Date()
);
// Step 3: Apply to risk assessment
const riskAssessmentPrompt = `
You are qe-risk-assessor. Before starting, apply these LEARNED RISK WEIGHTS:
${activeSignals.map(s => s.riskWeights.map(rw =>
`- ${rw.category}: Weight ${rw.weight} (${rw.evidence.percentageOfTotal}% of defects)`
).join('\n')).join('\n')}
RECOMMENDATIONS FROM PRODUCTION:
${activeSignals.flatMap(s => s.recommendations.forRiskAssessor).join('\n')}
Now assess risks for the following epic, with these weights pre-applied:
[EPIC CONTENT]
`;
await Task({
description: "Risk assessment with production learning",
prompt: riskAssessmentPrompt,
subagent_type: "qe-risk-assessor",
run_in_background: true
});
CLI Alternative
# PRODUCTION: Store risk signal
npx @claude-flow/cli@latest memory store \
--key "risk-signal-2026-Q1-$(date +%s)" \
--namespace "qcsd-memory/production-patterns/defect-weights" \
--value '{
"source": "production",
"target": "ideation",
"riskWeights": [
{"category": "payment-integration", "weight": 0.85}
]
}'
# IDEATION: Query risk signals
npx @claude-flow/cli@latest memory search \
--query "risk weights for ideation" \
--namespace "qcsd-memory/production-patterns"
# Route signals to learning coordinator
npx @claude-flow/cli@latest hooks route \
--task "Apply production risk weights to ideation" \
--source "qe-defect-predictor" \
--target "qe-learning-coordinator"
Loop 2: Production → Refinement (Tactical)
Memory Schema
interface SFDIPOTWeightSignal {
id: string;
timestamp: string;
source: "production";
target: "refinement";
loopType: "tactical";
factorWeights: {
factor: "Structure" | "Function" | "Data" | "Interfaces" | "Platform" | "Operations" | "Time";
weight: number; // 0.0 - 1.0
defectPercentage: number;
commonPatterns: string[]; // ["decimal precision", "null handling"]
}[];
featureContext: string; // "payment", "auth", "reporting"
recommendations: {
forProductFactorsAssessor: string[];
};
}
Storage Implementation
// PRODUCTION: Analyze defects by SFDIPOT factor
await mcp__agentic_qe__memory_store({
key: `sfdipot-weights-${featureArea}-${Date.now()}`,
namespace: "qcsd-memory/production-patterns/failure-modes",
value: {
id: `sfdipot-weights-${featureArea}-${Date.now()}`,
timestamp: new Date().toISOString(),
source: "production",
target: "refinement",
loopType: "tactical",
factorWeights: [
{
factor: "Data",
weight: 0.90,
defectPercentage: 60,
commonPatterns: [
"decimal precision in currency",
"null handling in optional fields",
"timezone conversion errors"
]
},
{
factor: "Interfaces",
weight: 0.75,
defectPercentage: 25,
commonPatterns: [
"API contract version mismatch",
"timeout handling missing",
"retry logic insufficient"
]
}
],
featureContext: "payment-transfers",
recommendations: {
forProductFactorsAssessor: [
"Weight Data factor at 0.90 for payment features",
"Always check: decimal precision, null handling, timezone",
"Weight Interfaces at 0.75 - API contracts need explicit validation"
]
}
}
});
Retrieval Implementation (Refinement Phase)
// REFINEMENT: Query SFDIPOT weights before product factors assessment
const sfdipotSignals = await mcp__agentic_qe__memory_query({
pattern: `sfdipot-weights-${featureArea}-*`,
namespace: "qcsd-memory/production-patterns/failure-modes"
});
const productFactorsPrompt = `
You are qe-product-factors-assessor. Apply these LEARNED FACTOR WEIGHTS:
FEATURE AREA: ${featureArea}
HISTORICAL DEFECT PATTERNS:
${sfdipotSignals.flatMap(s => s.factorWeights.map(fw =>
`${fw.factor}: ${fw.defectPercentage}% of defects
Common patterns: ${fw.commonPatterns.join(', ')}`
)).join('\n\n')}
WEIGHT THESE FACTORS HIGHER in your SFDIPOT assessment.
Now analyze the following story:
[STORY CONTENT]
`;
Loop 3: CI/CD → Development (Operational)
Memory Schema
interface TestHealthSignal {
id: string;
timestamp: string;
source: "cicd";
target: "development";
loopType: "operational";
flakyPatterns: {
pattern: string; // "shared database state"
frequency: number; // How often it causes flakiness
affectedTests: string[]; // Test file paths
rootCause: string;
fix: string; // "Use transaction rollback"
}[];
gateFailures: {
reason: string;
percentage: number;
trend: "increasing" | "stable" | "decreasing";
}[];
recommendations: {
forTestArchitect: string[];
antiPatterns: string[]; // Patterns to AVOID in new tests
};
}
Storage Implementation
// CI/CD: After quality gate evaluation, store patterns
await mcp__agentic_qe__memory_store({
key: `test-health-${sprint}-${Date.now()}`,
namespace: "qcsd-memory/cicd-patterns/flaky-tests",
value: {
id: `test-health-${sprint}-${Date.now()}`,
timestamp: new Date().toISOString(),
source: "cicd",
target: "development",
loopType: "operational",
flakyPatterns: [
{
pattern: "shared-database-state",
frequency: 0.80,
affectedTests: [
"tests/integration/user.test.ts",
"tests/integration/order.test.ts"
],
rootCause: "Tests share database without isolation",
fix: "Use transaction rollback or test containers"
},
{
pattern: "timing-dependent-assertions",
frequency: 0.15,
affectedTests: [
"tests/e2e/notification.test.ts"
],
rootCause: "setTimeout-based waits instead of polling",
fix: "Use waitFor() with polling instead of fixed delays"
}
],
gateFailures: [
{ reason: "flaky-tests", percentage: 60, trend: "stable" },
{ reason: "genuine-regression", percentage: 25, trend: "decreasing" },
{ reason: "environment-issues", percentage: 15, trend: "increasing" }
],
recommendations: {
forTestArchitect: [
"Generate tests with isolated database state (transaction rollback)",
"Use polling-based waits, never setTimeout",
"Mock external services by default"
],
antiPatterns: [
"AVOID: Shared database fixtures between tests",
"AVOID: Fixed setTimeout waits",
"AVOID: Tests that depend on execution order"
]
}
}
});
Retrieval Implementation (Development Phase)
// DEVELOPMENT: Query CI/CD health before generating tests
const cicdSignals = await mcp__agentic_qe__memory_query({
pattern: "test-health-*",
namespace: "qcsd-memory/cicd-patterns/flaky-tests"
});
const testArchitectPrompt = `
You are qe-test-architect. CRITICAL: Apply these LEARNED ANTI-PATTERNS:
FLAKY PATTERNS TO AVOID:
${cicdSignals.flatMap(s => s.flakyPatterns.map(fp =>
`❌ ${fp.pattern} (causes ${fp.frequency * 100}% of flakiness)
Root cause: ${fp.rootCause}
✅ Fix: ${fp.fix}`
)).join('\n\n')}
ANTI-PATTERNS (DO NOT GENERATE):
${cicdSignals.flatMap(s => s.recommendations.antiPatterns).join('\n')}
REQUIRED PATTERNS:
${cicdSignals.flatMap(s => s.recommendations.forTestArchitect).join('\n')}
Now generate tests for:
[CODE TO TEST]
`;
Loop 4: Development → Refinement (Quality Criteria)
Memory Schema
interface ACQualitySignal {
id: string;
timestamp: string;
source: "development";
target: "refinement";
loopType: "quality-criteria";
untestablePatterns: {
acPattern: string; // "user should be notified"
problem: string; // "No observable behavior"
frequency: number; // How often this pattern appears
betterPattern: string; // "User receives X notification within Y seconds"
}[];
coverageGaps: {
codeArea: string;
coveragePercentage: number;
rootCause: string; // "Vague AC", "Missing edge cases"
acImprovement: string;
}[];
recommendations: {
forRequirementsValidator: string[];
acTemplates: Record<string, string>; // Pattern → Template
};
}
Storage Implementation
// DEVELOPMENT: After coverage analysis, store AC quality signals
await mcp__agentic_qe__memory_store({
key: `ac-quality-${sprint}-${Date.now()}`,
namespace: "qcsd-memory/development-patterns/ac-problems",
value: {
id: `ac-quality-${sprint}-${Date.now()}`,
timestamp: new Date().toISOString(),
source: "development",
target: "refinement",
loopType: "quality-criteria",
untestablePatterns: [
{
acPattern: "user should be notified",
problem: "No observable behavior - how do we verify?",
frequency: 0.35,
betterPattern: "User receives [type] notification within [X] seconds via [channel], verifiable by [method]"
},
{
acPattern: "system should be fast",
problem: "No measurable criteria",
frequency: 0.20,
betterPattern: "API response time < [X]ms at p95 under [Y] concurrent users"
},
{
acPattern: "data should be secure",
problem: "Too vague to test",
frequency: 0.15,
betterPattern: "PII fields encrypted at rest (AES-256), in transit (TLS 1.3), masked in logs"
}
],
coverageGaps: [
{
codeArea: "notification-service",
coveragePercentage: 45,
rootCause: "AC says 'notify' but no testable criteria",
acImprovement: "Add: delivery confirmation, timing SLA, retry on failure"
}
],
recommendations: {
forRequirementsValidator: [
"Flag ACs containing 'should be notified' - require delivery mechanism",
"Flag ACs containing 'should be fast' - require p95 latency target",
"Flag ACs containing 'should be secure' - require specific controls"
],
acTemplates: {
"notification": "User receives [type] notification within [X] seconds via [channel], verifiable by [observable behavior]",
"performance": "Operation completes in < [X]ms at p95 under [Y] concurrent users",
"security": "[Data type] encrypted with [algorithm] at rest, [protocol] in transit, [masking] in logs"
}
}
}
});
Retrieval Implementation (Refinement Phase)
// REFINEMENT: Query AC quality signals before requirements validation
const acSignals = await mcp__agentic_qe__memory_query({
pattern: "ac-quality-*",
namespace: "qcsd-memory/development-patterns/ac-problems"
});
const requirementsValidatorPrompt = `
You are qe-requirements-validator. FLAG these KNOWN UNTESTABLE PATTERNS:
PATTERNS THAT CAUSED COVERAGE GAPS:
${acSignals.flatMap(s => s.untestablePatterns.map(up =>
`❌ Pattern: "${up.acPattern}"
Problem: ${up.problem}
Frequency: ${up.frequency * 100}% of ACs
✅ Better: "${up.betterPattern}"`
)).join('\n\n')}
AC TEMPLATES TO SUGGEST:
${Object.entries(acSignals[0]?.recommendations.acTemplates || {}).map(
([type, template]) => `${type}: "${template}"`
).join('\n')}
Now validate these acceptance criteria:
[AC CONTENT]
For any AC matching the untestable patterns, IMMEDIATELY FLAG IT and suggest the better pattern.
`;
Automatic Trigger Hooks
Hook Configuration
# .claude/hooks/cross-phase-memory.yaml
hooks:
# After production defect analysis
post-defect-analysis:
trigger: "qe-defect-predictor completes"
action:
- store_risk_weights
- notify_learning_coordinator
target_phases: [ideation, refinement]
# After CI/CD quality gate
post-quality-gate:
trigger: "qe-quality-gate completes"
action:
- store_flaky_patterns
- store_gate_failure_reasons
target_phases: [development]
# After coverage analysis
post-coverage-analysis:
trigger: "qe-coverage-specialist completes"
action:
- store_coverage_gaps
- store_ac_problems
target_phases: [refinement]
# At phase start - query relevant signals
pre-ideation:
trigger: "ideation phase starts"
action:
- query_production_risk_signals
- inject_into_agent_context
pre-refinement:
trigger: "refinement phase starts"
action:
- query_sfdipot_weights
- query_ac_quality_signals
- inject_into_agent_context
pre-development:
trigger: "development phase starts"
action:
- query_cicd_health_signals
- inject_into_agent_context
CLI Hook Commands
# Register post-task hook for defect analysis
npx @claude-flow/cli@latest hooks post-task \
--task-id "defect-analysis" \
--success true \
--action "store-cross-phase-signal" \
--target-namespace "qcsd-memory/production-patterns"
# Register pre-task hook for ideation
npx @claude-flow/cli@latest hooks pre-task \
--description "QCSD Ideation" \
--action "query-cross-phase-signals" \
--source-namespaces "qcsd-memory/production-patterns"
Memory Expiration & Cleanup
Expiration Policy
| Signal Type | Default TTL | Rationale |
|---|---|---|
| Risk weights | 90 days | Defect patterns change slowly |
| SFDIPOT weights | 90 days | Product factor risks stable |
| Flaky patterns | 30 days | CI/CD health changes quickly |
| AC quality | 60 days | Refinement practices evolve |
Cleanup Job
// Run weekly to clean expired signals
async function cleanupExpiredSignals() {
const namespaces = [
"qcsd-memory/production-patterns/defect-weights",
"qcsd-memory/production-patterns/failure-modes",
"qcsd-memory/cicd-patterns/flaky-tests",
"qcsd-memory/development-patterns/ac-problems"
];
for (const namespace of namespaces) {
const signals = await mcp__agentic_qe__memory_query({
pattern: "*",
namespace
});
for (const signal of signals) {
if (new Date(signal.expiresAt) < new Date()) {
await mcp__agentic_qe__memory_delete({
key: signal.id,
namespace
});
console.log(`Expired: ${signal.id}`);
}
}
}
}
Verification: Is the Loop Working?
Metrics to Track
interface FeedbackLoopMetrics {
loopId: string; // "loop-1-strategic"
// Input metrics
signalsGenerated: number; // How many signals stored
signalsConsumed: number; // How many signals queried
// Output metrics
recommendationsApplied: number; // Did target agent use them?
outcomesImproved: boolean; // Did defects decrease?
// Timing
avgSignalAge: number; // Days since signal created
consumptionLatency: number; // Time from store to query
}
Dashboard Query
// Check loop health
const loopHealth = await mcp__agentic_qe__memory_query({
pattern: "*",
namespace: "qcsd-memory/cross-phase-signals"
});
console.log(`
CROSS-PHASE FEEDBACK LOOP HEALTH
================================
Loop 1 (Strategic): ${countSignals(loopHealth, 'strategic')} signals
Loop 2 (Tactical): ${countSignals(loopHealth, 'tactical')} signals
Loop 3 (Operational): ${countSignals(loopHealth, 'operational')} signals
Loop 4 (QualityCrit): ${countSignals(loopHealth, 'quality-criteria')} signals
Oldest signal: ${getOldestSignal(loopHealth)}
Newest signal: ${getNewestSignal(loopHealth)}
`);
Summary
| Loop | Storage Namespace | Key Pattern | TTL |
|---|---|---|---|
| 1: Strategic | production-patterns/defect-weights |
risk-signal-* |
90d |
| 2: Tactical | production-patterns/failure-modes |
sfdipot-weights-* |
90d |
| 3: Operational | cicd-patterns/flaky-tests |
test-health-* |
30d |
| 4: Quality Criteria | development-patterns/ac-problems |
ac-quality-* |
60d |
Key Principle: Store at source phase, query at target phase, expire when stale.
Document created: 2026-01-25 Implementation specification for QCSD cross-phase memory