Skip to content

Buổi 16: Jira Integration + QA Knowledge Base

Mục Tiêu Buổi Học

Sinh viên sẽ xây dựng hệ thống quản lý issue lifecycle từ GitHub → Jira + QA Knowledge Base tự động compile từ CONTINUITY.md, giúp AI ngày càng thông minh qua feedback loop.


Phần 1: Lý Thuyết (20 phút)

Issue Lifecycle Automation

TaskFlow QA có 3 trạng thái issue:

┌──────────────────┐
│   Auto-Created   │  (Session 14: AI tạo từ test failure)
│   GitHub Issue   │
└────────┬─────────┘


┌──────────────────┐
│   Auto-Reviewed  │  (Session 15: AI review trên PR)
│   + Commented    │
└────────┬─────────┘


┌──────────────────┐
│   Synced to      │  (Session 16: Jira + Knowledge Base)
│   Jira + Memory  │
└────────┬─────────┘


┌──────────────────┐
│   Resolved       │  Next test cycle starts
└──────────────────┘

cm-continuity: Dual Brain Architecture

QA AI hiệu quả nhờ 2 kiểu memory:

1. Master Brain — Global Patterns

markdown
# CONTINUITY.md — Master Brain

## Common Bug Patterns (từ tất cả projects)

### Pattern 1: Email Validation
- Root Cause: No regex or regex incomplete (forgot .+@.+\..+)
- Appeared in: UserAPI (3 times), AuthService (2 times)
- Fix Template: Use validator library, unit tests for edge cases
- Learning: Always use library, never write custom regex

### Pattern 2: SQLite NULL Handling
- Root Cause: Forgot .notNull() constraint or != null check
- Appeared in: TaskTable (5 times), UserTable (2 times)
- Fix Template: Add .notNull() to schema, return default value
- Learning: SQLite default is NULL, must explicit handle

### Pattern 3: Async/Await Timing
- Root Cause: Missing await before promise-returning function
- Appeared in: API routes (7 times), Tests (4 times)
- Fix Template: Always await db.prepare().run(), add eslint rule
- Learning: Node 18+ strict rules, catch unhandled promise rejections

Benefit: Khi bug tương tự xuất hiện lần thứ 8, AI lookup từ master brain thay vì re-analyze.

2. Project Brain — Project-Specific

markdown
## CONTINUITY-TASKFLOW.md — Project Brain

### TaskFlow Bug Patterns

#### Bug 1: POST /api/users — Email Validation Missing
- Date: 2024-01-15
- Commit: abc123
- Error: TypeError: Cannot read property 'domain' of null
- Root Cause: validateEmail() checks length but not format
- Fix: import validator; use validator.isEmail(email)
- Test Added: test/api/users-validation.test.js
- Related: Pattern 1 from Master Brain

#### Bug 2: GET /api/tasks/:id — SQLite NULL Return
- Date: 2024-01-20
- Commit: def456
- Error: ReferenceError: Cannot read property 'title' of undefined
- Root Cause: Task.findById() returns undefined for deleted tasks
- Fix: Return { id, title: null } instead
- Test Added: test/api/tasks-deleted-task.test.js
- Related: Pattern 2 from Master Brain

Benefit: QA AI llearns project quirks (e.g., "TaskFlow always needs notNull on title field").

Why AI-Native QA Improves Over Time

Scenario A: Without Knowledge Base

Week 1: Found email validation bug #1
  - Analyze: 30 min + 3,000 tokens
  
Week 3: Found similar email bug #2
  - Analyze: 30 min + 3,000 tokens (NO learning!)
  
Week 5: Found third email bug #3
  - Analyze: 30 min + 3,000 tokens (STILL no learning!)
  
Total: 90 min + 9,000 tokens 🔴

Scenario B: With Knowledge Base (CONTINUITY.md)

Week 1: Found email validation bug #1
  - Analyze: 30 min + 3,000 tokens
  - Save to CONTINUITY.md: "Pattern: Email validation always needs library"
  
Week 3: Found similar email bug #2
  - Lookup CONTINUITY.md: 1 min + 50 tokens ✓
  - Match with Pattern 1: "Use validator library"
  - Fix immediately
  
Week 5: Found third email bug #3
  - Lookup CONTINUITY.md: 1 min + 50 tokens ✓
  - Match with Pattern 1: "Use validator library"
  - Fix immediately
  
Total: 32 min + 3,100 tokens 🟢
Savings: 58 min + 5,900 tokens (62% reduction!)

cm-notebooklm: Content Generation

CONTINUITY.md cung cấp raw QA knowledge. NotebookLM convert thành multiple formats:

Format 1: Podcast (Audio)

Episode 1: "Email Validation: The Most Common Bug"
- 15 min audio
- Covers Pattern 1
- Real examples from TaskFlow
- Actionable advice

Format 2: Study Guide (PDF)

# QA Study Guide for TaskFlow

## Chapter 1: Email Validation Bugs
- What goes wrong?
- How to test?
- Fix checklist
- Real TaskFlow code

Format 3: Flashcards (Quizlet)

Q: What's the most common bug in TaskFlow API?
A: Email validation missing format check. Use validator.isEmail()

Q: How to handle NULL in SQLite TaskFlow schema?
A: Add .notNull() constraint, return default value { id, title: null }

Phần 2: Thực Hành (60 phút)

Task 1: Viết scripts/jira-sync.js

Sync issue từ GitHub → Jira (hoặc GitHub Projects nếu không có Jira)

Tạo file: scripts/jira-sync.js

javascript
const https = require('https');
const fs = require('fs');

/**
 * Jira Sync for TaskFlow QA
 * Syncs GitHub issues to Jira
 * 
 * Usage: node scripts/jira-sync.js
 * 
 * Environment vars:
 * - JIRA_HOST: jira.company.com
 * - JIRA_USER: qa@company.com
 * - JIRA_API_TOKEN: xxxx (from Jira account)
 * - GITHUB_TOKEN: xxxx
 * - PROJECT_KEY: TASKFLOW (or TK)
 */

class JiraSync {
  constructor(config = {}) {
    this.jiraHost = process.env.JIRA_HOST || 'jira.company.com';
    this.jiraUser = process.env.JIRA_USER;
    this.jiraToken = process.env.JIRA_API_TOKEN;
    this.githubToken = process.env.GITHUB_TOKEN;
    this.githubOwner = process.env.GITHUB_OWNER || 'your-org';
    this.githubRepo = process.env.GITHUB_REPO || 'taskflow';
    this.projectKey = process.env.PROJECT_KEY || 'TASKFLOW';
    this.syncMap = {}; // GitHub issue ID → Jira issue key
  }

  /**
   * Get GitHub issues labeled 'bug' or 'test-failure'
   */
  async getGitHubIssues() {
    return this.makeRequest({
      hostname: 'api.github.com',
      path: `/repos/${this.githubOwner}/${this.githubRepo}/issues?labels=bug,test-failure&state=open`,
      method: 'GET',
      headers: {
        'Authorization': `token ${this.githubToken}`,
        'Accept': 'application/vnd.github.v3+json'
      }
    });
  }

  /**
   * Create issue in Jira
   */
  async createJiraIssue(githubIssue) {
    const issueBody = {
      fields: {
        project: { key: this.projectKey },
        summary: githubIssue.title,
        description: {
          version: 3,
          type: 'doc',
          content: [
            {
              type: 'paragraph',
              content: [
                {
                  type: 'text',
                  text: `Original GitHub Issue: #${githubIssue.number}\n\n${githubIssue.body}`
                }
              ]
            }
          ]
        },
        issuetype: { name: 'Bug' },
        labels: githubIssue.labels.map(label => label.name),
        priority: this.mapPriority(githubIssue),
        customfield_10000: githubIssue.html_url // Custom field: GitHub URL
      }
    };

    return this.makeRequest({
      hostname: this.jiraHost,
      path: '/rest/api/3/issues',
      method: 'POST',
      headers: {
        'Authorization': `Basic ${Buffer.from(`${this.jiraUser}:${this.jiraToken}`).toString('base64')}`,
        'Accept': 'application/json',
        'Content-Type': 'application/json'
      },
      body: JSON.stringify(issueBody)
    });
  }

  /**
   * Map GitHub issue to Jira priority
   */
  mapPriority(githubIssue) {
    const body = githubIssue.body.toLowerCase();
    
    if (body.includes('🔴 critical') || body.includes('critical')) {
      return { name: 'Highest' };
    }
    if (body.includes('🟠 high') || body.includes('high')) {
      return { name: 'High' };
    }
    if (body.includes('🟡 medium') || body.includes('medium')) {
      return { name: 'Medium' };
    }
    return { name: 'Low' };
  }

  /**
   * Generic HTTP request helper
   */
  makeRequest(options) {
    return new Promise((resolve, reject) => {
      const req = https.request(options, (res) => {
        let data = '';
        
        res.on('data', chunk => data += chunk);
        res.on('end', () => {
          try {
            if (data) {
              resolve(JSON.parse(data));
            } else {
              resolve({ status: res.statusCode });
            }
          } catch (e) {
            reject(new Error(`Failed to parse response: ${e.message}`));
          }
        });
      });

      req.on('error', reject);
      
      if (options.body) {
        req.write(options.body);
      }
      req.end();
    });
  }

  /**
   * Main sync workflow
   */
  async run() {
    try {
      console.log('🔄 Jira Sync started...\n');

      // Step 1: Get GitHub issues
      console.log('Step 1: Fetching GitHub issues...');
      const githubIssues = await this.getGitHubIssues();
      console.log(`✅ Found ${githubIssues.length} open issues\n`);

      if (githubIssues.length === 0) {
        console.log('No issues to sync.');
        return;
      }

      // Step 2: Create in Jira
      console.log('Step 2: Syncing to Jira...');
      let synced = 0;
      let failed = 0;

      for (const issue of githubIssues) {
        try {
          const jiraIssue = await this.createJiraIssue(issue);
          console.log(`✅ Created: ${jiraIssue.key} ← #${issue.number}`);
          this.syncMap[issue.number] = jiraIssue.key;
          synced++;
        } catch (error) {
          console.error(`❌ Failed to sync #${issue.number}: ${error.message}`);
          failed++;
        }
      }

      // Step 3: Save sync map
      console.log('\nStep 3: Saving sync map...');
      fs.writeFileSync(
        'sync-map.json',
        JSON.stringify(this.syncMap, null, 2)
      );
      console.log(`✅ Saved sync map\n`);

      console.log(`\n📊 Summary:`);
      console.log(`  Synced: ${synced}`);
      console.log(`  Failed: ${failed}`);
      console.log(`  Total:  ${synced + failed}`);

    } catch (error) {
      console.error('\n❌ ERROR:', error.message);
      process.exit(1);
    }
  }
}

// CLI
if (require.main === module) {
  const sync = new JiraSync();
  sync.run();
}

module.exports = JiraSync;

Task 2: Compile QA Knowledge Base từ CONTINUITY.md

Tạo file: scripts/compile-knowledge-base.js

javascript
const fs = require('fs');
const path = require('path');
const marked = require('marked'); // npm install marked

/**
 * Compile QA Knowledge Base
 * Reads CONTINUITY.md + CONTINUITY-TASKFLOW.md
 * Generates lessons.md for uploading to NotebookLM
 */

class KnowledgeBaseCompiler {
  constructor() {
    this.masterBrain = this.readFile('CONTINUITY.md');
    this.projectBrain = this.readFile('CONTINUITY-TASKFLOW.md');
  }

  readFile(filename) {
    const filepath = path.join(process.cwd(), filename);
    if (!fs.existsSync(filepath)) {
      console.warn(`⚠️  File not found: ${filename}`);
      return '';
    }
    return fs.readFileSync(filepath, 'utf-8');
  }

  /**
   * Extract bug patterns from CONTINUITY.md
   */
  extractPatterns() {
    const patterns = [];
    const lines = this.masterBrain.split('\n');

    let currentPattern = null;

    lines.forEach((line, idx) => {
      if (line.match(/^### Pattern \d+:/)) {
        currentPattern = {
          title: line.replace('### ', ''),
          rootCause: '',
          appeared: '',
          fixTemplate: '',
          learning: ''
        };
        patterns.push(currentPattern);
      } else if (currentPattern) {
        if (line.includes('Root Cause:')) {
          currentPattern.rootCause = line.replace('- Root Cause:', '').trim();
        } else if (line.includes('Appeared in:')) {
          currentPattern.appeared = line.replace('- Appeared in:', '').trim();
        } else if (line.includes('Fix Template:')) {
          currentPattern.fixTemplate = line.replace('- Fix Template:', '').trim();
        } else if (line.includes('Learning:')) {
          currentPattern.learning = line.replace('- Learning:', '').trim();
        }
      }
    });

    return patterns;
  }

  /**
   * Extract project-specific bugs
   */
  extractProjectBugs() {
    const bugs = [];
    const lines = this.projectBrain.split('\n');

    let currentBug = null;

    lines.forEach((line) => {
      if (line.match(/^#### Bug \d+:/)) {
        currentBug = {
          title: line.replace('#### ', ''),
          date: '',
          commit: '',
          error: '',
          rootCause: '',
          fix: '',
          test: '',
          related: ''
        };
        bugs.push(currentBug);
      } else if (currentBug) {
        if (line.includes('Date:')) currentBug.date = line.replace('- Date:', '').trim();
        if (line.includes('Commit:')) currentBug.commit = line.replace('- Commit:', '').trim();
        if (line.includes('Error:')) currentBug.error = line.replace('- Error:', '').trim();
        if (line.includes('Root Cause:')) currentBug.rootCause = line.replace('- Root Cause:', '').trim();
        if (line.includes('Fix:')) currentBug.fix = line.replace('- Fix:', '').trim();
        if (line.includes('Test Added:')) currentBug.test = line.replace('- Test Added:', '').trim();
        if (line.includes('Related:')) currentBug.related = line.replace('- Related:', '').trim();
      }
    });

    return bugs;
  }

  /**
   * Generate comprehensive lessons.md
   */
  generateLessons() {
    const patterns = this.extractPatterns();
    const bugs = this.extractProjectBugs();

    let lessons = `# TaskFlow QA Knowledge Base

**Generated from**: CONTINUITY.md + CONTINUITY-TASKFLOW.md  
**Purpose**: Train AI reviewer and QA team on recurring patterns  
**Use**: Upload to NotebookLM for podcast/study guide generation

---

## Table of Contents

1. [Common Bug Patterns](#common-patterns) — ${patterns.length} patterns
2. [TaskFlow-Specific Bugs](#taskflow-bugs) — ${bugs.length} bugs
3. [Learning Timeline](#timeline) — When bugs appeared
4. [Quick Reference](#quick-ref) — Fix checklist

---

## Common Bug Patterns

These patterns appear across multiple projects. When new bug found, check these first.

`;

    patterns.forEach((pattern, idx) => {
      lessons += `
### Pattern ${idx + 1}: ${pattern.title}

**Root Cause**: ${pattern.rootCause}

**Where It Appears**: ${pattern.appeared}

**How to Fix**: ${pattern.fixTemplate}

**Key Learning**: ${pattern.learning}

---
`;
    });

    lessons += `
## TaskFlow-Specific Bugs

Real bugs found in TaskFlow codebase with solutions.

`;

    bugs.forEach((bug, idx) => {
      lessons += `
### Bug ${idx + 1}: ${bug.title}

**Found**: ${bug.date} (Commit: \`${bug.commit}\`)

**Error Message**: \`${bug.error}\`

**Root Cause**: ${bug.rootCause}

**Solution Applied**: ${bug.fix}

**Test Coverage**: ${bug.test}

**Related Pattern**: ${bug.related}

---
`;
    });

    lessons += `
## Learning Timeline

When did we discover each pattern?

\`\`\`
${bugs.map(b => `${b.date} — ${b.title}`).join('\n')}
\`\`\`

---

## Quick Reference: Fix Checklist

Use this when reviewing new issues:

### Email Validation (Pattern 1)
- [ ] Using validator.isEmail() or similar library?
- [ ] Testing edge cases (subdomains, +alias, long domains)?
- [ ] Returning 400 with clear error message?

### SQLite NULL (Pattern 2)
- [ ] Schema has .notNull() for required fields?
- [ ] Queries handle NULL gracefully?
- [ ] Tests check NULL edge case?

### Async/Await (Pattern 3)
- [ ] All promise-returning functions have await?
- [ ] Error handling with try/catch?
- [ ] ESLint rule: no-floating-promises enabled?

---

## For NotebookLM

**How to use this file**:

1. Copy content of this file
2. Go to https://notebooklm.google.com
3. Create new notebook
4. Paste this content
5. Click "Generate" → Choose:
   - **Study Guide**: For QA training material
   - **Podcast**: For team listening (15-20 min episodes)
   - **Flashcards**: For quick memorization

**Expected outputs**:
- 📚 Study Guide: 20-30 pages, structured lessons
- 🎙️ Podcast: 2-3 episodes, conversational tone, real examples
- 🎯 Flashcards: 50+ Q&A pairs for Quizlet

---

## Stats

- **Master Brain Patterns**: ${patterns.length}
- **Project Brain Bugs**: ${bugs.length}
- **AI Learning Curve**: Improves 10% per new pattern documented
- **Token Savings**: 50 tokens (lookup) vs 3,000 tokens (re-analyze)

`;

    return lessons;
  }

  /**
   * Main workflow
   */
  run() {
    console.log('📚 Knowledge Base Compiler started...\n');

    console.log('Step 1: Reading Master Brain...');
    console.log(`✅ Read CONTINUITY.md (${this.masterBrain.length} chars)\n`);

    console.log('Step 2: Reading Project Brain...');
    console.log(`✅ Read CONTINUITY-TASKFLOW.md (${this.projectBrain.length} chars)\n`);

    console.log('Step 3: Extracting patterns and bugs...');
    const patterns = this.extractPatterns();
    const bugs = this.extractProjectBugs();
    console.log(`✅ Found ${patterns.length} patterns, ${bugs.length} bugs\n`);

    console.log('Step 4: Generating lessons.md...');
    const lessons = this.generateLessons();
    fs.writeFileSync('lessons.md', lessons);
    console.log(`✅ Saved lessons.md (${lessons.length} chars)\n`);

    console.log('✅ Complete!\n');
    console.log('Next steps:');
    console.log('1. Copy lessons.md content');
    console.log('2. Go to https://notebooklm.google.com');
    console.log('3. Create notebook and paste content');
    console.log('4. Generate: Study Guide, Podcast, Flashcards');
  }
}

// CLI
if (require.main === module) {
  const compiler = new KnowledgeBaseCompiler();
  compiler.run();
}

module.exports = KnowledgeBaseCompiler;

Task 3: Sample CONTINUITY Files

Create example knowledge base files:

File: CONTINUITY.md

markdown
# CONTINUITY.md — Master Brain (Global Patterns)

Patterns that appear across ALL projects.

## Common Bug Patterns

### Pattern 1: Email Validation
- Root Cause: No regex or incomplete regex (missing .+@.+\..+)
- Appeared in: UserAPI (3 times), AuthService (2 times), TaskFlow (5 times)
- Fix Template: Use validator library (npm install validator), write unit tests
- Learning: Never write custom regex for validation. Always use library.

### Pattern 2: SQLite NULL Handling
- Root Cause: Forgot .notNull() constraint or != null check in code
- Appeared in: TaskTable (5 times), UserTable (3 times), ProjectTable (2 times)
- Fix Template: Add .notNull() to schema, check for null in handler, return default value
- Learning: SQLite default is NULL. Must be explicit about NOT NULL.

### Pattern 3: Async/Await Timing
- Root Cause: Missing await before promise-returning function
- Appeared in: API routes (7 times), Tests (4 times), Scripts (3 times)
- Fix Template: Always await db.prepare().run(), use eslint rule no-floating-promises
- Learning: Node 18+ is strict. Unhandled promise rejections crash process.

File: CONTINUITY-TASKFLOW.md

markdown
# CONTINUITY-TASKFLOW.md — Project Brain (TaskFlow-Specific)

Bugs found specifically in TaskFlow codebase.

## TaskFlow Bug Log

#### Bug 1: POST /api/users — Email Validation Missing
- Date: 2024-01-15
- Commit: abc123def456
- Error: TypeError: Cannot read property 'domain' of null
- Root Cause: validateEmail() checks length but not format. Email "not-an-email" passed validation.
- Fix: import validator from 'validator'; use validator.isEmail(email)
- Test Added: test/api/users-validation.test.js (covers: normal email, no @, missing domain)
- Related: Pattern 1 (Email Validation)

#### Bug 2: GET /api/tasks/:id — SQLite NULL Return
- Date: 2024-01-20
- Commit: def456ghi789
- Error: Cannot read property 'title' of undefined (when accessing null task)
- Root Cause: Task.findById() returns undefined when task deleted. Code assumes always object.
- Fix: Return { id: 123, title: null } instead of undefined. Add null check in handler.
- Test Added: test/api/tasks-deleted-task.test.js
- Related: Pattern 2 (SQLite NULL)

Task 4: Demo — End-to-End Workflow

Step 1: Run Jira Sync

bash
export JIRA_HOST=jira.company.com
export JIRA_USER=qa@company.com
export JIRA_API_TOKEN=xxx
export GITHUB_TOKEN=xxx
export PROJECT_KEY=TASKFLOW

node scripts/jira-sync.js

Output:

✅ Found 5 open issues
✅ Created: TASKFLOW-123 ← #42
✅ Created: TASKFLOW-124 ← #43
✅ Saved sync map

Step 2: Compile Knowledge Base

bash
node scripts/compile-knowledge-base.js

Output:

✅ Read CONTINUITY.md (2,500 chars)
✅ Read CONTINUITY-TASKFLOW.md (3,200 chars)
✅ Found 3 patterns, 2 bugs
✅ Saved lessons.md (8,900 chars)

Step 3: Upload to NotebookLM

  1. Open https://notebooklm.google.com
  2. Create notebook
  3. Copy lessons.md content → paste into notebook
  4. Click "Generate" → select "Podcast"
  5. Listen to AI-generated podcast about TaskFlow QA patterns

Expected Podcast:

Episode 1: "The Three Most Common TaskFlow Bugs"
Duration: 18 min

Host: "Today we're covering the three patterns that keep breaking
TaskFlow tests. First up: email validation..."

[AI explains Pattern 1 with real TaskFlow examples]

[AI explains Pattern 2 with code snippets]

[AI explains Pattern 3 with test cases]

Host: "Remember these three patterns for next sprint!"

Kiến Thức Áp Dụng

cm-continuity: Working Memory Protocol

Session 1 (Week 1):
  Test fails with email bug
  → Analyze (3,000 tokens)
  → Save to CONTINUITY.md (50 tokens)

Session 2 (Week 3):
  Similar email bug appears
  → Lookup CONTINUITY.md (50 tokens) ✓
  → Match pattern (10 tokens)
  → Fix immediately
  
Savings: 2,990 tokens (90% reduction!)

cm-notebooklm: Knowledge Multiplication

CONTINUITY.md (raw data)

lessons.md (structured)

NotebookLM generates:
  - Podcast (audio learning)
  - Study guide (reading)
  - Flashcards (memorization)
  - Summary (quick ref)
  
Result: 1 input → 4 formats

📝 Quiz (5 câu)

  1. Lifecycle: Nêu 4 trạng thái của issue từ auto-created đến resolved
  2. Master vs Project Brain: Khác nhau gì giữa CONTINUITY.md (master) vs CONTINUITY-TASKFLOW.md (project)?
  3. Token Savings: Nếu bug đầu tiên tốn 3,000 tokens, sau khi lưu pattern, bug tương tự tốn bao nhiêu?
  4. NotebookLM: Có bao nhiêu format output từ NotebookLM? Nêu tên.
  5. Jira Sync: Script sync dùng HTTP method nào để tạo issue trong Jira?

🏠 Homework (30 phút)

  1. Create CONTINUITY.md: Document 3 patterns từ previous lessons (email, NULL, async)
  2. Log a bug: Create CONTINUITY-TASKFLOW.md with 1 real TaskFlow bug
  3. Run compile: node scripts/compile-knowledge-base.js → generate lessons.md
  4. Upload NotebookLM: Paste lessons.md → generate podcast
  5. Listen & Review: Listen to AI podcast, verify accuracy

📚 Resources


🎯 Long-Term Impact

By End of Course (Session 16):

  • Session 14: Auto-create issues from tests
  • Session 15: Auto-review code quality
  • Session 16: Auto-learn patterns for future issues

Improvement Curve:

Week 1: Manual QA (8 hours/day)

Week 4: AI-assisted (4 hours/day)

Week 8: AI-native (1 hour/day, 90% automated)

Week 12: AI learning loop
         (Gets better each sprint)

Token Economics:

  • Manual debugging: 3,000 tokens/bug × 10 bugs/month = 30,000 tokens
  • AI with memory: 50 tokens (lookup) × 8 bugs + 3,000 tokens (new pattern) = 3,400 tokens
  • Savings: 26,600 tokens (89% reduction) per month

🎓 Reflections

What Changed Over 16 Sessions

AspectSession 1Session 16
Test SpeedManualCI/CD
DebuggingGuessworkScientific (Phase 1)
Code ReviewSpottingAutomated scanning
KnowledgePer-projectGlobal patterns
AI LearningStatelessMemory-based
Time/Bug15 min30 sec auto + 5 min fix

Takeaway

QA automation isn't about replacing humans. It's about building memory systems so each bug teaches the next generation of tests.

┌─ Old QA ─┐
│ Bug #1   │ → Fix → Forget
│ Bug #2   │ → Fix → Forget (same pattern!)
│ Bug #3   │ → Fix → Forget
└──────────┘

┌─ New QA ─┐
│ Bug #1   │ → Fix → Save pattern
│ Bug #2   │ → Lookup pattern → Fix 10x faster
│ Bug #3   │ → Lookup pattern → Fix 10x faster
│ Bug #4   │ → Lookup → Prevent before it happens!
└──────────┘

Welcome to AI-native QA.

Powered by CodyMaster × VitePress