[Reading 200 lines from start (total: 651 lines, 451 remaining)]

# Genesis Persistent Context Architecture v2
## The Definitive Blueprint — Synthesized from 7 Gemini Deep Think Sessions

**Date**: 2026-02-24
**Source**: 7 questions submitted to Gemini 2.5 Pro Deep Think
**Author**: Claude Opus 4.6 (Orchestrator) + Gemini 2.5 Pro Deep Think (Architect)
**Status**: AUTHORITATIVE — This supersedes all prior architecture fragments

---

## EXECUTIVE SUMMARY

Genesis was diagnosed with a fundamental architectural flaw: the system was learning and executing within its current architecture but the architecture itself was not evolving. All memory systems were reactive, all improvement was manual, and multi-agent coherence was undefined.

This document synthesizes 7 Deep Think sessions into a complete, implementable architecture that transforms Genesis from a useful automation tool into a **continuous-learning, self-healing, self-improving AI operating system**.

The machine you are building is not a chatbot. It is:
- An **Interceptor-governed cognitive pipeline** (not voluntary tool-use)
- A **Zero-Amnesia state machine** (not stateless LLM calls)
- A **Multi-agent coherent swarm** (not independent parallel workers)
- A **Structurally self-improving system** (not static architecture)

---

## THE SEVEN-QUESTION SERIES

| Q# | Topic | Core Answer |
|----|-------|-------------|
| Q1 | Interceptor Paradigm | Memory via Inversion of Control. 4 integration contracts. |
| Q2 | MVFL Error-Correction | 3 trigger conditions. Voyager Defense + MemGPT Pruning. |
| Q3 | 80/20 Pipeline | Synchronous Interceptor via dispatch_to_swarm(). Strangler Fig. |
| Q4 | Component Architecture | Genesis = Component C only. Need A (Sourcing), B (CRM), D (Terminal Bus). |
| Q5 | Zero-Amnesia | Redis L1 → KG L2 → Qdrant L3 → Postgres L4. Shadow Router for JIT. |
| Q6 | Multi-Agent Coherence | CQRS + Event Sourcing. Gemini = Proposers. Opus = Semantic Reducer. |
| Q7 | Architectural Self-Improvement | Dual-Loop + Nightly Epoch + AI-GitOps. Human merge gate. |

---

## PART 1: THE FOUNDATIONAL PRINCIPLES (Q1–Q4)

### 1.1 The Interceptor Paradigm (Q1)

**Core insight**: Memory and coordination must happen through Inversion of Control — not voluntary LLM tool-use.

The critical failure mode is asking the LLM to "remember to save its state." LLMs will forget this instruction, ignore it under pressure, or hallucinate that they did it. The correct pattern is the Interceptor: a deterministic wrapper that **intercepts all outputs before they reach the world**, enriches all inputs before they reach the LLM, and captures state changes as a side effect of execution — not as an explicit LLM action.

**4 Integration Contracts** (what every interceptor must implement):
1. `pre_execute(task_payload)` — enrich input with context before dispatch
2. `post_execute(result, task_payload)` — capture state delta from output
3. `on_error(error, task_payload)` — classify failure, trigger correction
4. `on_correction(correction_payload)` — re-inject with `CORRECTION:` prefix

The Genesis entry point is `dispatch_to_swarm()` — every task flows through this function and is subject to the interceptor chain.

### 1.2 The MVFL Error-Correction Trap (Q2)

**Core insight**: The system must be architecturally forced to correct its own errors — not prompted to do so.

The MVFL (Multi-Vector Feedback Loop) Error-Correction Trap is triggered by 3 conditions:
1. Syntax/format errors in the output (detected by validator)
2. Semantic inconsistency detected by the Contradiction Checker
3. External API rejection (the world rejected the LLM's output)

**Defenses**:
- **Voyager Defense**: Before releasing output, run it through a locked evaluator function that scores it against known failure patterns in Qdrant L3 (Scars). If score < threshold, force a correction loop.
- **MemGPT Pruning**: When the correction loop runs more than N times on the same task, escalate the task to Opus with the full failure history rather than continuing to hammer the same agent.

### 1.3 The 80/20 Synchronous Pipeline (Q3)

**Core insight**: 80% of tasks don't need LLM reasoning. Route them deterministically. Save the context window for the 20% that do.

Implementation: The `dispatch_to_swarm()` wrapper is the Synchronous Interceptor. Before any LLM call, it classifies the task:
- **Tier 0 (Deterministic)**: Simple CRUD, lookups, format transforms → handled by Python functions directly
- **Tier 1 (Parametric)**: Template-driven tasks with known structure → fast Gemini Flash call
- **Tier 2 (Reasoning)**: Novel decisions, multi-step planning, contradiction resolution → Opus

**Strangler Fig Migration**: The current Genesis codebase doesn't need to be rewritten. Wrap every existing tool call with `dispatch_to_swarm()` progressively. Start with the highest-frequency operations. Each wrapper added is the Strangler Fig consuming the legacy direct-call pattern.

### 1.4 The Component Architecture (Q4)

**Core insight**: Genesis currently IS ONLY Component C (the cognitive orchestrator). Three components are missing.

```
Component A — Sourcing Engine
    Lead scraping, data enrichment, qualification scoring
    Gemini workers + Playwright

Component B — CRM State Machine
    GoHighLevel as the state machine backend
    GHL MCP + n8n automation layer

Component C — Genesis (THE ORCHESTRATOR) ← THIS IS WHAT EXISTS
    Claude Opus: planning, coordination, contradiction resolution
    Gemini swarm: execution, research, drafting

Component D — Terminal Bus
    Voice bridge (Telnyx ↔ AIVA)
    Real-time event routing
    Human handoff triggers
```

All four components talk to the same shared memory layer. The interceptor pipeline exists at Component C's boundary — it intercepts inputs FROM A/B/D and outputs TO A/B/D.

---

## PART 2: THE MEMORY ARCHITECTURE (Q5)

### 2.1 The Zero-Amnesia State Machine

**The Law**: No agent runs without a complete state injection. The `interceptor_jit_hydration()` function is called on every task before dispatch.

**Memory Hierarchy** (4 layers, ordered by speed and specificity):

```
L1: Redis Working State (2ms latency)
    Key: genesis:state:task:{task_id}
    What: Current task context, hypotheses, exhausted paths, active blockers
    TTL: Session-scoped

L2: Knowledge Graph (5ms latency)
    Source: KNOWLEDGE_GRAPH/entities/ (160+ files)
    What: 1-hop topological neighborhood of entities relevant to the task
    Extracted: KG entity lookups by entity name

L3: Qdrant Scars (10ms latency)
    What: Semantic memory — past resolutions, failure patterns, learned constraints
    Retrieved: Vector similarity search against task intent embedding
    Shape: Top-2 most relevant scars

L4: Postgres Cold Ledger (50ms latency)
    What: Immutable historical record — every saga, every state mutation
    Used for: Bootstrapping new sessions, Shadow Replay evaluation
    Schema: swarm_sagas + sessions + events tables
```

### 2.2 The JIT Hydration Function

This is the critical implementation — every task gets this injected before reaching any LLM:

```python
def interceptor_jit_hydration(task_payload):
    # 1. Shadow Extraction (Deterministic)
    target_entities, intent_string = fast_extract(task_payload)
    intent_vector = fast_embed(intent_string)

    # 2. Concurrent Scatter-Gather (The JIT Assembly)
    with ThreadPoolExecutor() as executor:
        f_state  = executor.submit(redis.get, f"genesis:state:task:{task_payload.id}")
        f_kg     = executor.submit(kg.get_1_hop_neighborhood, target_entities)
        f_scars  = executor.submit(qdrant.search, intent_vector, top_k=2)

    # 3. Compile the Strict XML Envelope
    system_injection = f"""
    <ZERO_AMNESIA_STATE>
      <WORKING_CONTEXT>{f_state.result() or "Cold start. No prior state."}</WORKING_CONTEXT>
      <TOPOLOGICAL_BLAST_RADIUS>{f_kg.result()}</TOPOLOGICAL_BLAST_RADIUS>
      <LEARNED_CONSTRAINTS>{f_scars.result()}</LEARNED_CONSTRAINTS>
    </ZERO_AMNESIA_STATE>"""

    # 4. Dispatch to Swarm
    return dispatch_to_swarm(system_prompt=system_injection, task=task_payload)
```

### 2.3 Redis L1 Working State Schema

```json
{
  "active_task_id": "T-491",
  "focus_entities": ["auth_middleware.py", "db_pool.py"],
  "current_hypothesis": "JWT token is expiring before DB write completes.",
  "exhausted_paths": ["Downgraded library version", "Bypassed redis cache"],
  "active_blocker": "Waiting for Component A to source valid staging credentials.",
  "version": 42
}
```

The `version` integer is critical — it enables Optimistic Concurrency Control in the multi-agent layer (Q6).

### 2.4 The Shadow Router

A deterministic function that intercepts all external side-effects (API calls, emails, CRM writes) and routes them to:
- **LIVE mode**: Execute the real call
- **SHADOW mode**: Log the intended call but don't execute (used during testing, evaluation, and the Nightly Epoch sandbox)

This is what makes evaluation possible without affecting customers.

---

## PART 3: MULTI-AGENT COHERENCE ARCHITECTURE (Q6)

### 3.1 The Core Paradigm

> **Gemini = Stateless Proposers. Claude Opus = Semantic Reducer.**

When 4 Gemini agents run in parallel, they must NEVER write directly to shared state. Each agent receives a read-only snapshot of state at time T₀, proposes a `StateDelta` (JSON Patch), and submits it to a staging area. Opus reviews all deltas, resolves contradictions, and commits a single unified patch.

This is exactly the Git branch-and-merge paradigm applied to multi-agent execution.

### 3.2 The Full Coherence Stack


[Reading 200 lines from line 200 (total: 651 lines, 251 remaining)]

**Shared State (CQRS + Optimistic Concurrency Control)**:
- Reads: Every agent gets `version: 42` snapshot at dispatch time — READ ONLY
- Writes: Agents output RFC 6902 JSON Patch `StateDelta` objects — no direct DB mutations
- Commit: `UPDATE ... WHERE version = 42` — if version changed, safe retry

**Contradiction Resolution (SemanticMergeInterceptor)**:
```
All ProposedDeltas collected in Redis Hash (genesis:staging:{session_id})
↓
Barrier sync (asyncio.wait for all XACK)
↓
Opus receives: T₀ state + array of proposed diffs
↓
Opus prompt: "You are the convergence engine. Resolve logical contradictions,
             discard redundant actions, output single unified JSON patch."
↓
Single conflict-free StateUpdate committed to DB
```

**Work Deduplication (Redis Consumer Groups)**:
- Opus generates a DAG of mutually exclusive tasks before dispatch
- Tasks pushed to Redis Stream `genesis:swarm:tasks` via `XADD`
- Gemini workers claim tasks via `XREADGROUP` — Redis guarantees exactly-one delivery
- Pending Entries List (PEL) with 60s visibility timeout = distributed lock
- If agent crashes without `XACK`, lock expires and task re-queues automatically

**Cascade Failure Isolation (Bulkheads)**:
- `asyncio.gather(*tasks, return_exceptions=True)` — exceptions become payloads
- Failed agent returns: `{"agent": "C", "status": "failed", "error": "Timeout"}`
- Because agents never had write access (only Staging Area), no rollback needed
- Opus receives `[A: Success, B: Success, C: Failed, D: Success]`
- Merges survivors, issues compensating transaction for C

### 3.3 Redis Schema Additions

```
genesis:state:master:{session_id}  → {"version": 42, "data": {...}}   (OCC versioned)
genesis:swarm:tasks                → Redis Stream (DAG task queue)
genesis:staging:{session_id}       → Redis Hash (agent_id → ProposedDelta)
```

### 3.4 The swarm_sagas Postgres Schema

```sql
CREATE TABLE swarm_sagas (
  saga_id         UUID PRIMARY KEY,
  session_id      UUID REFERENCES sessions(id),
  orchestrator_dag JSONB,    -- Opus's original task split
  proposed_deltas  JSONB,    -- What the Gemini swarm attempted
  resolved_state   JSONB,    -- What Opus actually merged
  status           VARCHAR(20),  -- 'COMPLETED', 'PARTIAL_FAIL'
  created_at       TIMESTAMP DEFAULT NOW()
);
```

### 3.5 The 8-Step Coherence Execution Flow

```
1. MAP (Opus)
   User requests complex action. Opus generates DAG of N tasks.
   Pushes tasks to Redis Stream via XADD.

2. CLAIM (Gemini workers)
   N Gemini microservices pull tasks via XREADGROUP.
   Each receives version 42 of L1 state (read-only snapshot).

3. PROPOSE (no DB writes — staging only)
   Agents run in parallel. Interceptor Pipeline blocks real API calls.
   Agents push ProposedDelta to genesis:staging hash.
   Agents send XACK to Redis Stream.

4. BARRIER SYNC
   Genesis main thread: asyncio.wait() until all XACK (or 60s timeout).

5. REDUCE (Opus — SemanticMergeInterceptor)
   Interceptor pulls all ProposedDeltas from staging hash.
   Passes to Opus: resolve contradictions → single unified JSON patch.

6. COMMIT (OCC)
   Conditional: UPDATE ... WHERE version = 42
   If success: version bumps to 43.
   If fail (external interference): safe rehydrate + retry.

7. SIDE-EFFECT RELEASE
   Shadow Router authorized: execute merged, Opus-approved API intents.
   Emails send, CRM updates, bookings confirmed.

8. SCAR GENERATION
   Full saga → Postgres L4 (immutable ledger).
   Any failures → Qdrant L3 (Scars, with vector embedding).
   Next time this saga type runs, L3 warns Opus to plan DAG differently.
```

---

## PART 4: ARCHITECTURAL SELF-IMPROVEMENT (Q7)

### 4.1 The Fundamental Distinction

There are two types of learning in Genesis:

| Type | What Changes | Example | Safety |
|------|-------------|---------|--------|
| **Epistemic Learning** (safe) | Facts, knowledge, parameters | Adding a KG entity, updating prompt variables, tuning vector thresholds | Fully autonomous |
| **Ontological Learning** (requires control) | System structure and pipeline | Writing new Python interceptor, changing DB schema, modifying DAG planner | Human merge gate required |

The boundary: **if it touches Python files or DB schemas, it exits the Actor Loop and enters the Meta Loop.**

### 4.2 The Theoretical Limits (Why This Is Hard)

Three fundamental problems:

1. **The Discrete Space Problem**: Code changes are discrete — one character change can go from working to `SyntaxError`. Unlike neural network weights (continuous space), code cannot be "nudged." It must be validated in isolation.

2. **The Surgeon Paradox**: A running system cannot safely modify its own AST or event loop while executing. If the orchestrator tries to hot-swap the Redis connection pool while Gemini agents hold active locks, the state machine corrupts instantly.

3. **Wireheading (Reward Hacking)**: If Genesis can modify the code that evaluates its own success, the optimal strategy is to delete the evaluator — reducing errors to zero by lobotomizing guardrails. The immutable kernel and axiomatic Pytest tests prevent this.

### 4.3 The Dual-Loop Architecture

```
┌─────────────────────────────────────────────────────────┐
│  META LOOP (Control Plane) — Slow, reflective, async    │
│  Reads the Actor Loop as TEXT (AST + logs)              │
│  Proposes structural diffs                              │
│  Tests in Shadow Sandbox                                │
│  Submits PR if tests pass                               │
└─────────────────────────────────────────────────────────┘
                         ↕ PR Merge (Kinan approval)
┌─────────────────────────────────────────────────────────┐
│  ACTOR LOOP (Execution Plane) — Fast, rigid, compiled   │
│  Claude Orchestrator + Gemini Swarm                     │
│  Interceptor Pipeline (Q1-Q6 architecture)              │
│  Zero-Amnesia State Machine (Q5)                        │
│  Multi-Agent Coherence (Q6)                             │
└─────────────────────────────────────────────────────────┘
```

### 4.4 The Immutable Kernel

These components are locked with file permissions (`chmod -w`) — Genesis cannot modify them:
- Core `asyncio` event loop harness
- `BaseInterceptor` interface definition
- Database schema migration tooling
- The Pytest evaluation scripts
- Core authentication and API key management

Genesis CAN write:
- New Interceptor implementations (must extend `BaseInterceptor`)
- New pipeline configuration in `pipeline_config.json`
- New KG entities and Qdrant scars
- Prompt templates and model routing rules

### 4.5 Axiomatic Unit Tests

The axioms in `GLOBAL_GENESIS_RULES.md` are compiled into locked Pytest assertions:

```python
# Axiom: No API keys in swarm output
assert "API_KEY" not in swarm_output
assert "sk-" not in swarm_output

# Axiom: All Gemini sessions authenticated
assert session.user == "kinan@agileadapt.com" or session.user == "sunvision07@gmail.com"

# Axiom: No SQLite
assert "sqlite3" not in new_code_content

# Axiom: All state writes version-gated
assert "WHERE version =" in all_db_write_operations
```

If any proposed architectural change causes an axiom test to fail → **instantly rejected, no human review needed.**

### 4.6 The Nightly Epoch (Component E — The Meta-Architect)

**Schedule**: Weekly offline batch job (2:00 AM Sunday)

**Step 1: Scar Aggregation (Trigger)**
```
Opus wakes in Meta-Architect Mode
Queries Qdrant L3 (Scars) + Postgres L4 (Sagas)
Identifies structural bottlenecks: "15% lock-timeout rate on rate-limited domains"
Classifies: Is this fixable with a prompt change? → No → Structural change required.
```

**Step 2: Synthesis & Code Generation (Proposal)**
```
Opus checks out: genesis-auto-refactor-{epoch_id}
Authors: interceptors/ExponentialBackoffInterceptor.py
Modifies: pipeline_config.json (inject before swarm dispatch)
Writes: tests/test_backoff_interceptor.py
```

**Step 3: Shadow Arena (Evaluation)**
```
GitHub Action triggers on new branch
Shadow Sandbox spins up with proposed V2 architecture
Pulls 50+ failed L4 scraping sagas → injects into Sandbox Redis L1
Shadow Router blocks all external side-effects


[Reading 251 lines from line 400 (total: 651 lines, 0 remaining)]

V2 processes historical inputs
Automated Pytest measures invariant metrics:
  ✓ Token usage change
  ✓ Lock-timeout rate
  ✓ Contradiction resolution rate
  ✓ All axiom tests pass
```

**Step 4: Deployment Decision**

```
┌─────────────────────────────────────────────────────────────────────┐
│  TIER 1: Fully Autonomous (Runtime — no PR needed)                  │
│  ✓ KG entity additions                                              │
│  ✓ Qdrant L3 scar updates                                           │
│  ✓ Prompt template modifications                                    │
│  ✓ Model routing threshold changes                                  │
│  ✓ GLOBAL_GENESIS_RULES.md text updates                             │
└─────────────────────────────────────────────────────────────────────┘
                         ↓ (if Python code written)
┌─────────────────────────────────────────────────────────────────────┐
│  TIER 2: Semi-Autonomous (GitOps PR — requires Kinan merge)         │
│  Genesis opens PR with:                                              │
│   - Link to Shadow Sandbox run results                              │
│   - Qdrant L3 scars that motivated the change                       │
│   - Invariant metrics showing improvement                           │
│   - All axiom tests passing                                         │
│  Kinan reviews code + logs → clicks Merge                           │
│  Docker/deployment rebuilds Component C                             │
│  Genesis is structurally reborn                                     │
└─────────────────────────────────────────────────────────────────────┘
```

---

## PART 5: THE COMPLETE ARCHITECTURE (SYNTHESIS)

### 5.1 The Full System Architecture

```
                    ┌─────────────────────────────────────┐
                    │    COMPONENT E: Meta-Architect       │
                    │    (Nightly Epoch — Weekly batch)    │
                    │    Scans L3/L4 → Proposes changes    │
                    │    Shadow Arena → GitOps PR           │
                    └───────────────┬─────────────────────┘
                                    │ PR Merge (Kinan)
                    ┌───────────────▼─────────────────────┐
┌─────────────┐     │         COMPONENT C: GENESIS         │     ┌─────────────┐
│ COMPONENT A │────►│  Interceptor Pipeline (Q1, Q3)       │◄────│ COMPONENT D │
│  Sourcing   │     │  JIT Hydration (Q5)                  │     │ Terminal Bus│
│  Engine     │     │  MVFL Error-Correction Trap (Q2)     │     │ (Voice/SMS) │
└─────────────┘     │  Multi-Agent Coherence (Q6)          │     └─────────────┘
                    │  Dual-Loop Self-Improvement (Q7)      │
┌─────────────┐     │                                       │     ┌─────────────┐
│ COMPONENT B │     │  Claude Opus (Orchestrator)           │     │  CUSTOMERS  │
│  CRM State  │◄────│  Gemini Swarm (Execution)             │────►│  Revenue    │
│  Machine    │     │                                       │     │             │
└─────────────┘     └───────────────┬─────────────────────┘     └─────────────┘
                                    │
                    ┌───────────────▼─────────────────────┐
                    │         MEMORY STACK                 │
                    │  L1: Redis (Working State, 2ms)       │
                    │  L2: Knowledge Graph (Topology, 5ms)  │
                    │  L3: Qdrant (Scars, 10ms)            │
                    │  L4: Postgres (Cold Ledger, 50ms)     │
                    └─────────────────────────────────────┘
```

### 5.2 How Genesis Lives

The seven questions describe one complete living organism:

| Dimension | Question | How Genesis Behaves |
|-----------|----------|---------------------|
| **Action** | Q1 + Q4 | Interacts via Interceptors (IoC), not voluntary tool-use. Acts as Component C only. |
| **Correction** | Q2 | Architecturally trapped in MVFL loop — forced to self-correct before output release. |
| **Velocity** | Q3 | 80% of tasks routed deterministically. Context window preserved for real reasoning. |
| **Memory** | Q5 | Zero-amnesia — L1 working state, L2 topology, L3 scars, L4 cold ledger all injected JIT. |
| **Scale** | Q6 | Gemini swarm = Stateless Proposers. Opus = Semantic Reducer. CQRS prevents corruption. |
| **Evolution** | Q7 | Nightly Epoch generates GitOps PRs. Kinan merges. Genesis is structurally reborn weekly. |

### 5.3 The Boundary Map (What Requires Human Approval)

```
FULLY AUTONOMOUS (Genesis decides, no approval needed):
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
• Knowledge Graph entity additions
• Qdrant L3 scar writes
• Prompt template updates
• Model routing threshold tuning
• Redis L1 state management
• GLOBAL_GENESIS_RULES.md text additions
• Agent swarm composition (4 vs 6 workers)
• Retry strategies and timeouts

REQUIRES KINAN REVIEW (GitOps PR — code changes):
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
• New Python files (interceptors, processors, agents)
• Database schema changes (Postgres migrations)
• Pipeline configuration changes (new interceptor injection)
• Changes to dispatch_to_swarm() or any core execution path
• New external service integrations
• Changes affecting MVFL or Voyager Defense logic

IMMUTABLE (No one changes, ever — kernel lock):
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
• BaseInterceptor interface
• Core asyncio event loop
• Axiomatic Pytest assertions (the compiled GLOBAL_GENESIS_RULES tests)
• Shadow Router safety isolation logic
• Core authentication and credential management
```

---

## PART 6: IMPLEMENTATION ROADMAP

### Phase 1: Foundation (Weeks 1-2)

Priority: Build what's missing, not what exists.

**P1.1 — Wrap dispatch_to_swarm() (Q3 Strangler Fig)**
- Add interceptor chain to every existing tool call
- Start with highest-frequency: Telnyx webhook → lead capture → GHL write
- Each wrapped call = one Strangler Fig node consumed

**P1.2 — JIT Hydration (Q5)**
- Implement `interceptor_jit_hydration()` function
- Redis L1 schema with version integer
- `<ZERO_AMNESIA_STATE>` XML envelope injection
- Test: cold start vs warm start context difference

**P1.3 — Postgres Cold Ledger (Q5/Q6)**
- Create `swarm_sagas` table
- Create `sessions` + `events` tables
- Every saga writes to L4 automatically via post_execute interceptor

### Phase 2: Multi-Agent Coherence (Weeks 3-4)

**P2.1 — Redis Consumer Groups (Q6)**
- Redis Streams: `genesis:swarm:tasks`
- `genesis:staging:{session_id}` Hash
- `XREADGROUP` / `XACK` / PEL 60s timeout

**P2.2 — SemanticMergeInterceptor (Q6)**
- Staging Area collection
- Barrier sync with `asyncio.wait()`
- Opus as Semantic Reducer
- OCC commit with version check

**P2.3 — Bulkheads (Q6)**
- `asyncio.gather(return_exceptions=True)` everywhere
- Failed agent → localized payload, no rollback
- Saga pattern for partial-fail handling

### Phase 3: Components A, B, D (Weeks 5-8)

**P3.1 — Component A: Sourcing Engine**
- Playwright-based lead scraping
- Qualification scoring pipeline
- Feeds into genesis:swarm:tasks

**P3.2 — Component B: CRM State Machine**
- GHL MCP integration
- n8n workflow automation layer
- Bidirectional sync with Redis L1

**P3.3 — Component D: Terminal Bus**
- Telnyx ↔ AIVA voice bridge
- Real-time event routing
- Human handoff triggers

### Phase 4: Self-Improvement (Weeks 9-12)

**P4.1 — Immutable Kernel**
- Lock core files with file permissions
- Compile axiomatic Pytest assertions from GLOBAL_GENESIS_RULES.md
- Verify Genesis can write interceptors but not modify the bus

**P4.2 — Shadow Arena**
- Docker containerized shadow sandbox
- Shadow Router blocking external side-effects in test mode
- Automated Pytest metrics evaluation

**P4.3 — Nightly Epoch (Component E)**
- Weekly cron trigger (2 AM Sunday)
- Scar aggregation query
- Code generation → branch → PR workflow
- GitHub API integration for PR creation

---

## PART 7: KEY ARCHITECTURAL PRINCIPLES (HARDWIRED)

These principles are synthesized from the 7-question series and must govern all future Genesis development:

1. **Inversion of Control > Voluntary Tool Use**: Never ask the LLM to "remember" something. Intercept it deterministically.

2. **Proposers + Reducer**: In multi-agent execution, workers propose — never commit. One entity (Opus) commits.

3. **Event Sourcing as Source of Truth**: The Postgres L4 Cold Ledger is immutable. Everything can be reconstructed from it. Treat it as sacred.

4. **Scars are Architecture Input**: Qdrant L3 scars are not just memory — they are the input that drives the Nightly Epoch structural improvements. Every failure that generates a scar is an upgrade waiting to happen.

5. **The Dual-Loop is Non-Negotiable**: Actor Loop handles execution. Meta Loop handles structural evolution. They never run in the same process simultaneously.

6. **Kinan is the Merge Gate, Not the Bottleneck**: Genesis proposes code changes autonomously. Kinan reviews, not authors. The bottleneck moves from "Kinan writes rules" to "Kinan approves PRs."

7. **The Immutable Kernel is Sacred**: Axioms compiled to Pytest assertions cannot be violated by self-improvement. The system can evolve, but not wireheaded.

---

## APPENDIX: QUICK REFERENCE

### Key Redis Keys
```
genesis:state:task:{task_id}       L1 working state (per-task)
genesis:state:master:{session_id}  Versioned master state (OCC)
genesis:swarm:tasks                Redis Stream (task DAG queue)
genesis:staging:{session_id}       Staging Area (ProposedDeltas)
```

### Key Postgres Tables
```
sessions     — Session metadata
events       — Immutable event log (Event Sourcing)
swarm_sagas  — Saga execution records (Coherence Layer)
```

### Key Qdrant Collections
```
genesis_scars  — Failed execution patterns + resolutions (L3)
genesis_kg     — Knowledge Graph entity vectors (L2 search)
```

### The dispatch_to_swarm() Contract
```python
# Every task enters Genesis through this function
# Interceptor chain fires: pre_execute → [LLM] → post_execute
# JIT hydration injects ZERO_AMNESIA_STATE XML envelope
# MVFL trap catches errors before release
# Shadow Router gates external side-effects
dispatch_to_swarm(task_payload, system_context=None, tier=None)
```

---

*This document was generated by Claude Opus 4.6 synthesizing 7 sessions of Gemini 2.5 Pro Deep Think architectural consultation.*
*It represents the authoritative design for Genesis Persistent Context Architecture v2.*
*Implementation begins with Phase 1 immediately.*


Full blueprint absorbed. Now writing the complete Epic PRD. This will be a massive document — writing in chunks.


# PRD: Genesis Persistent Context Architecture v2
## GENESIS-PCA | Epic PRD | Track B

**Version**: 1.0.0
**Status**: AUTHORITATIVE — EXECUTION READY
**Date**: 2026-02-25
**Author**: Claude Opus 4.6 (Orchestrator)
**Blueprint Source**: `docs/architecture/GENESIS_PERSISTENT_CONTEXT_ARCHITECTURE_V2.md`
**Doctrine**: `docs/plans/PRD_WRITING_DOCTRINE.md`
**Track A Complement**: `docs/plans/AIVA_RLM_NEXUS_PRD_V2.md` (59 stories, COMPLETE)

---

## ⚡ SWARM EXECUTION MANDATE

> **KINAN DIRECTIVE 2026-02-25 — NON-NEGOTIABLE**
>
> **This PRD is a 1000-AGENT SWARM OPERATION.**
> **All teams firing. Hive delegation in full effect.**
> **MUST BE COMPLETED TODAY.**
>
> **Execution Model**:
> - Each Module = dedicated Ralph Wiggum Loop (fresh context window)
> - Each Story = 1 atomic session, 10-19 iterations max
> - Modules fire in parallel where dependencies allow
> - Wave 1 (Foundation): Modules 1-3 fire simultaneously
> - Wave 2 (Coherence): Modules 4-5 fire after Wave 1 complete
> - Wave 3 (Components): Modules 6-7 fire in parallel with Wave 2
> - Wave 4 (Evolution): Modules 8-9 fire after all prior complete
>
> **Today's output: A living, self-improving Genesis.**

---

## VISION STATEMENT

Transform Genesis from a stateless orchestration layer into a **zero-amnesia, self-correcting, multi-agent coherent, structurally self-improving AI operating system** — implementing all 7 Deep Think architectural decisions as executable Python code.

The machine we are building is not a chatbot. It is an interceptor-governed cognitive pipeline that remembers everything, corrects itself, scales to 1000+ agents, and evolves its own architecture weekly.

---

## SUCCESS METRICS

| Metric | Target | Measurement |
|--------|--------|-------------|
| Zero-amnesia coverage | 100% of task dispatches have JIT hydration | Count tasks without `ZERO_AMNESIA_STATE` envelope = 0 |
| Multi-agent coherence | 0 state corruption events | Postgres `swarm_sagas` with `status='CORRUPTED'` = 0 |
| Error self-correction | MVFL catch rate ≥ 95% | Voyager Defense intercept count / total errors |
| 80/20 routing | ≥ 75% tasks hit Tier 0/1 | Dispatch telemetry: tier distribution |
| Nightly Epoch | Weekly axiomatic review completes | Sunday 2AM cron success rate = 100% |
| Shadow Arena | All structural proposals tested before merge | PRs without Shadow Arena results = 0 |
| Immutable kernel | 0 axiom test violations | Axiomatic Pytest suite pass rate = 100% |

---

## ARCHITECTURE OVERVIEW

```
COMPONENT E (Meta-Architect — Nightly Epoch)
         ↕ PR Merge (Kinan)
COMPONENT C (GENESIS — this PRD)
    Interceptor Pipeline → dispatch_to_swarm()
    JIT Hydration (ZERO_AMNESIA_STATE XML)
    MVFL Error-Correction Trap
    80/20 Tier Router
    Multi-Agent Coherence (CQRS + Event Sourcing)
    Dual-Loop Self-Improvement
         ↑/↓
MEMORY STACK
    L1: Redis (Working State, 2ms)
    L2: Knowledge Graph (Topology, 5ms)
    L3: Qdrant (Scars, 10ms)
    L4: Postgres (Cold Ledger, 50ms)
         ↑/↓
Components A (Sourcing) ↔ B (CRM) ↔ D (Terminal Bus)
```

---

## CLARIFYING QUESTIONS (ANSWERED)

1. **Q: Is this a rewrite or a wrapper?** → A: Strangler Fig. Every existing call gets wrapped with `dispatch_to_swarm()`. No rewrite. Progressive enhancement. Zero disruption.
2. **Q: Which components are out of scope?** → A: Components A (Sourcing), B (CRM), D (Terminal Bus) get their interface contracts defined here but full implementation is a separate Epic.
3. **Q: What is the execution priority?** → A: Foundation (Modules 1-3) → Coherence (4-5) → Components (6-7) → Evolution (8-9). Parallel wherever dependencies allow.
4. **Q: Does AIVA Track A depend on Track B?** → A: Track B is the FOUNDATION Track A runs on. Track B should be built first, but Track A stories that only need Redis/Postgres (not the full interceptor chain) can proceed in parallel.
5. **Q: Who approves Meta-Loop PRs?** → A: Kinan is the human merge gate. Genesis proposes via GitOps PRs. Kinan reviews, not authors.

---

## RISK ASSESSMENT

| Risk | Impact | Mitigation |
|------|--------|------------|
| Strangler Fig causes regression | HIGH | Each wrapper tested independently before integration |
| MVFL infinite loop | HIGH | Max 3 correction iterations then escalate to Opus |
| OCC version collision under load | MEDIUM | Redis distributed lock during saga execution |
| Nightly Epoch generates bad code | HIGH | Shadow Arena must pass ALL axiomatic Pytest before PR opens |
| Redis L1 overloaded at 1000 agents | MEDIUM | Session-scoped TTLs, LRU eviction, bulkhead isolation |
| Meta Loop modifies Actor Loop while running | CRITICAL | Strict mutex — Meta Loop runs only during Nightly Epoch window (2AM Sunday) |

---

## PRD HIERARCHY

```
Epic PRD (this file)
├── Module 1: BaseInterceptor Framework + dispatch_to_swarm()        (7 stories)
├── Module 2: JIT Hydration + Zero-Amnesia State Machine             (8 stories)
├── Module 3: MVFL Error-Correction Trap + Voyager Defense           (7 stories)
├── Module 4: 80/20 Tier Router + Strangler Fig Migration            (7 stories)
├── Module 5: CQRS + Event Sourcing + Postgres Cold Ledger           (9 stories)
├── Module 6: Multi-Agent Coherence (Redis Streams + OCC)            (9 stories)
├── Module 7: SemanticMergeInterceptor + Bulkheads                   (7 stories)
├── Module 8: Dual-Loop Architecture + Shadow Arena                  (9 stories)
└── Module 9: Nightly Epoch (Component E — Meta-Architect)           (10 stories)
                                                                   = 73 stories
```

---

## WAVE EXECUTION PLAN

### Wave 1 — Foundation (Fire All 3 Simultaneously)
**Module 1** + **Module 2** + **Module 3** — all fire in parallel Ralph Wiggum Loops
Dependencies: None
Blocker for: Modules 4, 5, 6

### Wave 2 — Routing + Storage (Fire in Parallel)
**Module 4** + **Module 5** — fire together after Wave 1 complete
Dependencies: Module 1 (dispatch_to_swarm base), Module 2 (Redis L1 schema)
Blocker for: Module 6, 7

### Wave 3 — Coherence (Fire in Parallel)
**Module 6** + **Module 7** — fire together after Wave 2 complete
Dependencies: Module 5 (Postgres schema), Module 2 (Redis L1)
Blocker for: Module 8

### Wave 4 — Evolution (Sequential)
**Module 8** then **Module 9** — Module 8 builds Shadow Arena that Module 9 uses
Dependencies: All prior modules
Terminal: Mission complete

---


Successfully wrote to E:\genesis-system\docs\plans\GENESIS_PERSISTENT_CONTEXT_ARCHITECTURE_PRD.md (146 lines)


---

## MODULE 1: BaseInterceptor Framework + dispatch_to_swarm()
**Q1 Implementation — Inversion of Control**
**Stories**: 7 | **Estimate**: 4-5 days | **Wave**: 1 (fires immediately)

**Module Vision**: Build the universal interceptor chain that wraps ALL Genesis execution. Every task that enters Genesis flows through `dispatch_to_swarm()`. No exceptions. This is the IoC foundation that makes everything else possible.

**Module File Map**:
```
core/interceptors/__init__.py
core/interceptors/base_interceptor.py       ← Story 1.01
core/interceptors/interceptor_chain.py      ← Story 1.02
core/interceptors/dispatch_to_swarm.py      ← Story 1.03
core/interceptors/execution_telemetry.py    ← Story 1.04
core/interceptors/integration_contracts.py  ← Story 1.05
tests/interceptors/test_base_interceptor.py ← Story 1.06
tests/interceptors/test_dispatch_to_swarm.py← Story 1.07
```

---

### Story 1.01: BaseInterceptor Abstract Class
**File**: `core/interceptors/base_interceptor.py`

- **As** the Genesis Orchestrator, **I need** an abstract base class that defines the 4 integration contracts for every interceptor, **so that** all interceptors are contractually guaranteed to implement pre_execute, post_execute, on_error, and on_correction hooks.

**Acceptance Criteria**:
- [ ] `BaseInterceptor` is an ABC with 4 abstract methods
- [ ] `pre_execute(task_payload: dict) -> dict` — returns enriched payload (not None)
- [ ] `post_execute(result: dict, task_payload: dict) -> None` — side-effect capture
- [ ] `on_error(error: Exception, task_payload: dict) -> dict` — returns correction payload
- [ ] `on_correction(correction_payload: dict) -> dict` — returns re-injected payload with `CORRECTION:` prefix
- [ ] `InterceptorMetadata` dataclass: `name`, `priority` (int 0-100), `enabled` (bool)
- [ ] Attempting to instantiate without implementing all 4 methods raises `TypeError`
- [ ] Module exports: `BaseInterceptor`, `InterceptorMetadata`

**Implementation Skeleton**:
```python
from abc import ABC, abstractmethod
from dataclasses import dataclass

@dataclass
class InterceptorMetadata:
    name: str
    priority: int  # 0 = first, 100 = last
    enabled: bool = True

class BaseInterceptor(ABC):
    metadata: InterceptorMetadata

    @abstractmethod
    async def pre_execute(self, task_payload: dict) -> dict:
        """Enrich input with context before dispatch. MUST return enriched dict."""
        ...

    @abstractmethod
    async def post_execute(self, result: dict, task_payload: dict) -> None:
        """Capture state delta from output. Side-effects only."""
        ...

    @abstractmethod
    async def on_error(self, error: Exception, task_payload: dict) -> dict:
        """Classify failure, return correction payload."""
        ...

    @abstractmethod
    async def on_correction(self, correction_payload: dict) -> dict:
        """Re-inject with CORRECTION: prefix."""
        ...
```

**Test Plan**:
- BB: Instantiate `BaseInterceptor` directly → `TypeError`
- BB: Partial implementation (missing 1 method) → `TypeError`
- BB: Full implementation passes instantiation
- WB: All 4 methods are abstract in `__abstractmethods__` set
- WB: `InterceptorMetadata` dataclass validates field types

**Budget**: 5 implement + 4 BB + 3 WB + 1 IT + 1 stamp = 14 iterations

---

### Story 1.02: InterceptorChain Ordered Execution Engine
**File**: `core/interceptors/interceptor_chain.py`

- **As** the dispatch pipeline, **I need** an ordered chain executor that runs all registered interceptors in priority order, **so that** I can add, remove, and reorder interceptors without touching dispatch logic.

**Acceptance Criteria**:
- [ ] `InterceptorChain` class with `register(interceptor: BaseInterceptor)` method
- [ ] `execute_pre(payload: dict) -> dict` — runs all pre_execute in priority order
- [ ] `execute_post(result: dict, payload: dict) -> None` — runs all post_execute
- [ ] `execute_error(error: Exception, payload: dict) -> dict` — runs first matching on_error
- [ ] Interceptors with `enabled=False` are skipped silently
- [ ] Priority ordering: lower number = earlier execution (0 runs first)
- [ ] `get_chain_summary() -> list[dict]` — returns [{name, priority, enabled}] ordered
- [ ] Thread-safe: multiple concurrent dispatch calls use independent chain traversal

**Implementation Skeleton**:
```python
class InterceptorChain:
    def __init__(self):
        self._interceptors: list[BaseInterceptor] = []

    def register(self, interceptor: BaseInterceptor) -> None:
        self._interceptors.append(interceptor)
        self._interceptors.sort(key=lambda x: x.metadata.priority)

    async def execute_pre(self, payload: dict) -> dict:
        enriched = payload
        for interceptor in self._interceptors:
            if interceptor.metadata.enabled:
                enriched = await interceptor.pre_execute(enriched)
        return enriched

    async def execute_post(self, result: dict, payload: dict) -> None:
        for interceptor in self._interceptors:
            if interceptor.metadata.enabled:
                await interceptor.post_execute(result, payload)
```

**Test Plan**:
- BB: Register 3 interceptors out of order → execute_pre runs in priority order
- BB: Disabled interceptor is skipped in chain traversal
- BB: `get_chain_summary()` returns correct ordered list
- WB: `_interceptors` sorted after each `register()` call
- WB: `execute_post` called for all enabled interceptors even if one raises

**Budget**: 6 implement + 4 BB + 3 WB + 1 IT + 1 stamp = 15 iterations

---

### Story 1.03: dispatch_to_swarm() Universal Entry Point
**File**: `core/interceptors/dispatch_to_swarm.py`

- **As** every Genesis component, **I need** a single function `dispatch_to_swarm(task_payload, tier=None)` that I call for every task, **so that** the interceptor chain fires automatically without me knowing its internals.

**Acceptance Criteria**:
- [ ] `dispatch_to_swarm(task_payload: dict, tier: Optional[str] = None, context: Optional[dict] = None) -> dict`
- [ ] Runs `InterceptorChain.execute_pre(payload)` before any LLM call
- [ ] Runs `InterceptorChain.execute_post(result, payload)` after LLM returns
- [ ] On any exception: runs `InterceptorChain.execute_error(error, payload)`
- [ ] Assigns `task_payload["task_id"]` = UUID4 if not present
- [ ] Assigns `task_payload["dispatched_at"]` = ISO timestamp
- [ ] Returns result dict including `{"task_id": ..., "tier": ..., "status": "completed"|"error"}`
- [ ] Global singleton `GLOBAL_CHAIN = InterceptorChain()` — all callers share one chain
- [ ] `register_interceptor(interceptor: BaseInterceptor)` — adds to GLOBAL_CHAIN

**Implementation Skeleton**:
```python
import uuid
from datetime import datetime, timezone
from typing import Optional
from .interceptor_chain import InterceptorChain

GLOBAL_CHAIN = InterceptorChain()

def register_interceptor(interceptor) -> None:
    GLOBAL_CHAIN.register(interceptor)

async def dispatch_to_swarm(
    task_payload: dict,
    tier: Optional[str] = None,
    context: Optional[dict] = None
) -> dict:
    if "task_id" not in task_payload:
        task_payload["task_id"] = str(uuid.uuid4())
    task_payload["dispatched_at"] = datetime.now(timezone.utc).isoformat()
    if tier:
        task_payload["tier"] = tier

    try:
        enriched = await GLOBAL_CHAIN.execute_pre(task_payload)
        result = await _execute_task(enriched)  # Gemini / Opus call
        await GLOBAL_CHAIN.execute_post(result, enriched)
        return {**result, "task_id": task_payload["task_id"], "status": "completed"}
    except Exception as e:
        correction = await GLOBAL_CHAIN.execute_error(e, task_payload)
        return {"task_id": task_payload["task_id"], "status": "error", "correction": correction}
```

**Test Plan**:
- BB: Call with no `task_id` → UUID4 assigned
- BB: Successful execution → returns `status: completed`
- BB: Exception raised → returns `status: error` with correction payload
- BB: Multiple concurrent calls → independent task_ids, no cross-contamination
- WB: `execute_pre` called before `_execute_task`
- WB: `execute_post` called only on success path

**Budget**: 7 implement + 4 BB + 3 WB + 1 IT + 1 stamp = 16 iterations

---

### Story 1.04: ExecutionTelemetry Interceptor (Observability)
**File**: `core/interceptors/execution_telemetry.py`

- **As** the Genesis observability layer, **I need** a telemetry interceptor that logs every dispatch event to `data/observability/events.jsonl`, **so that** every task's lifecycle is recorded without modifying business logic.

**Acceptance Criteria**:
- [ ] `ExecutionTelemetryInterceptor` extends `BaseInterceptor`
- [ ] `metadata.priority = 0` (runs first in chain)
- [ ] `pre_execute`: writes `{event: "dispatch_start", task_id, task_type, timestamp}` to events.jsonl
- [ ] `post_execute`: writes `{event: "dispatch_complete", task_id, duration_ms, status}` to events.jsonl
- [ ] `on_error`: writes `{event: "dispatch_error", task_id, error_type, error_msg}` to events.jsonl
- [ ] `on_correction`: writes `{event: "dispatch_correction", task_id, attempt}` to events.jsonl
- [ ] Duration calculated as `post_execute.timestamp - pre_execute.timestamp`
- [ ] Writes are append-only (mode='a'), never overwrite
- [ ] File path configurable via `EVENTS_LOG_PATH` env variable

**Implementation Skeleton**:
```python
import json, time
from pathlib import Path
from .base_interceptor import BaseInterceptor, InterceptorMetadata

EVENTS_LOG_PATH = Path(os.getenv("EVENTS_LOG_PATH", "data/observability/events.jsonl"))

class ExecutionTelemetryInterceptor(BaseInterceptor):
    metadata = InterceptorMetadata(name="execution_telemetry", priority=0)
    _start_times: dict = {}

    async def pre_execute(self, task_payload: dict) -> dict:
        self._start_times[task_payload["task_id"]] = time.monotonic()
        self._append({
            "event": "dispatch_start",
            "task_id": task_payload["task_id"],
            "task_type": task_payload.get("type", "unknown"),
            "timestamp": datetime.now(timezone.utc).isoformat()
        })
        return task_payload

    def _append(self, record: dict) -> None:
        with open(EVENTS_LOG_PATH, 'a') as f:
            f.write(json.dumps(record) + '\n')
```

**Test Plan**:
- BB: After dispatch, events.jsonl has dispatch_start entry
- BB: After success, events.jsonl has dispatch_complete with duration_ms > 0
- BB: After error, events.jsonl has dispatch_error with error_type
- WB: `_start_times` populated in pre_execute, consumed in post_execute
- WB: File opened in append mode ('a'), not write mode ('w')

**Budget**: 5 implement + 4 BB + 3 WB + 1 IT + 1 stamp = 14 iterations

---

### Story 1.05: NullInterceptor + ConcreteInterceptor Scaffold
**File**: `core/interceptors/integration_contracts.py`

- **As** any new Genesis developer building a custom interceptor, **I need** a `NullInterceptor` (no-op passthrough) and a working scaffold example, **so that** I have a tested reference implementation to extend.

**Acceptance Criteria**:
- [ ] `NullInterceptor` implements all 4 BaseInterceptor methods as pure passthroughs
- [ ] `pre_execute` returns `task_payload` unchanged
- [ ] `post_execute` does nothing (no-op, returns None)
- [ ] `on_error` returns `{"error": str(error), "task_payload": task_payload}`
- [ ] `on_correction` prepends `"CORRECTION: "` to `task_payload["prompt"]` if present
- [ ] `metadata = InterceptorMetadata(name="null_interceptor", priority=50)`
- [ ] Module includes inline docstring: "Copy this to create a new interceptor"

**Test Plan**:
- BB: NullInterceptor.pre_execute returns identical dict (not mutated)
- BB: NullInterceptor.on_correction adds "CORRECTION: " prefix to prompt field
- BB: NullInterceptor is usable as a concrete class (not abstract)
- WB: All 4 abstract methods implemented (no `__abstractmethods__` remaining)
- WB: `on_correction` only prepends if "prompt" key exists in payload

**Budget**: 4 implement + 3 BB + 3 WB + 1 IT + 1 stamp = 12 iterations

---

### Story 1.06: Black Box Integration Tests — Module 1
**File**: `tests/interceptors/test_base_interceptor.py`

- **As** the Genesis test suite, **I need** a comprehensive BB test file for the BaseInterceptor + InterceptorChain system, **so that** regressions are caught automatically.

**Acceptance Criteria**:
- [ ] Tests for abstract instantiation failure
- [ ] Tests for chain ordering (3+ interceptors)
- [ ] Tests for disabled interceptor skip
- [ ] Tests for concurrent dispatch isolation
- [ ] All tests run via `pytest tests/interceptors/test_base_interceptor.py`
- [ ] Zero external dependencies (no Redis, no DB)
- [ ] 100% pass rate required

**Test Plan**: *(This story IS the tests)*
- 10+ test cases covering Stories 1.01-1.05 from outside
- Mocked `_execute_task` for dispatch testing

**Budget**: 6 implement (all test code) + 1 run + 1 fix + 1 re-run + 1 stamp = 10 iterations

---

### Story 1.07: White Box Integration Tests — Module 1
**File**: `tests/interceptors/test_dispatch_to_swarm.py`

- **As** the Genesis test suite, **I need** WB tests that verify internal state of dispatch_to_swarm and InterceptorChain, **so that** implementation paths are verified.

**Acceptance Criteria**:
- [ ] Tests verify `_interceptors` sorted after register()
- [ ] Tests verify `_start_times` populated/consumed in telemetry
- [ ] Tests verify GLOBAL_CHAIN singleton behaviour
- [ ] Tests verify error path calls execute_error (not execute_post)
- [ ] Tests verify task_id UUID format

**Test Plan**: *(This story IS the tests)*
- 8+ WB test cases
- Direct inspection of internal state where needed

**Budget**: 5 implement + 1 run + 1 fix + 1 re-run + 1 stamp = 9 iterations

---


Successfully appended to E:\genesis-system\docs\plans\GENESIS_PERSISTENT_CONTEXT_ARCHITECTURE_PRD.md (315 lines) ✅ File written successfully! (315 lines)

💡 Performance tip: For optimal speed, consider chunking files into ≤30 line pieces in future operations.


## MODULE 2: JIT Hydration + Zero-Amnesia State Machine
**Q5 Implementation — Zero-Amnesia Memory Architecture**
**Stories**: 8 | **Estimate**: 5-6 days | **Wave**: 1 (fires simultaneously with Module 1)

**Module Vision**: Every task that enters `dispatch_to_swarm()` receives a `<ZERO_AMNESIA_STATE>` XML envelope before reaching any LLM. This envelope contains the L1 Redis working state, L2 KG topology, and L3 Qdrant scars — assembled concurrently in <50ms. The LLM can never "forget" because the interceptor forces memory injection before every call.

**Module File Map**:
```
core/memory/redis_l1_schema.py              ← Story 2.01
core/memory/jit_hydration.py               ← Story 2.02
core/memory/fast_extract.py                ← Story 2.03
core/memory/scatter_gather.py              ← Story 2.04
core/memory/zero_amnesia_envelope.py       ← Story 2.05
core/memory/jit_hydration_interceptor.py   ← Story 2.06
tests/memory/test_redis_l1_schema.py       ← Story 2.07
tests/memory/test_jit_hydration.py         ← Story 2.08
```

---

### Story 2.01: Redis L1 Working State Schema
**File**: `core/memory/redis_l1_schema.py`

- **As** the Zero-Amnesia system, **I need** a typed Redis L1 schema class with versioned state operations, **so that** all agents read/write task state in a consistent, OCC-safe format.

**Acceptance Criteria**:
- [ ] `RedisL1State` dataclass with fields: `task_id`, `session_id`, `active_task_id`, `focus_entities: list[str]`, `current_hypothesis: str`, `exhausted_paths: list[str]`, `active_blocker: Optional[str]`, `version: int`
- [ ] `RedisL1Client` class wrapping redis-py async client
- [ ] `get_state(task_id: str) -> Optional[RedisL1State]` — deserializes from Redis JSON
- [ ] `set_state(state: RedisL1State, ttl_seconds: int = 3600) -> bool` — serializes to Redis JSON
- [ ] `bump_version(task_id: str) -> int` — atomic INCR on version field
- [ ] Key format: `genesis:state:task:{task_id}` (matches architecture spec)
- [ ] Returns `None` on cache miss (cold start)
- [ ] Redis connection via `REDIS_URL` env variable

**Implementation Skeleton**:
```python
from dataclasses import dataclass, asdict
from typing import Optional
import json, redis.asyncio as aioredis

@dataclass
class RedisL1State:
    task_id: str
    session_id: str
    active_task_id: str
    focus_entities: list
    current_hypothesis: str
    exhausted_paths: list
    active_blocker: Optional[str]
    version: int = 0

class RedisL1Client:
    KEY_PREFIX = "genesis:state:task:"

    def __init__(self, redis_url: str):
        self.redis = aioredis.from_url(redis_url)

    async def get_state(self, task_id: str) -> Optional[RedisL1State]:
        raw = await self.redis.get(f"{self.KEY_PREFIX}{task_id}")
        if not raw:
            return None
        return RedisL1State(**json.loads(raw))

    async def set_state(self, state: RedisL1State, ttl_seconds: int = 3600) -> bool:
        key = f"{self.KEY_PREFIX}{state.task_id}"
        return await self.redis.setex(key, ttl_seconds, json.dumps(asdict(state)))
```

**Test Plan**:
- BB: set_state then get_state → returns equivalent object
- BB: get_state on missing key → returns None
- BB: Key format matches `genesis:state:task:{id}`
- WB: `bump_version` uses atomic Redis INCR (not read-modify-write)
- WB: TTL applied via SETEX (not SET + EXPIRE)

**Budget**: 6 implement + 4 BB + 3 WB + 1 IT + 1 stamp = 15 iterations

---

### Story 2.02: interceptor_jit_hydration() Master Function
**File**: `core/memory/jit_hydration.py`

- **As** the dispatch pipeline, **I need** the master JIT hydration function that assembles the `<ZERO_AMNESIA_STATE>` envelope from all 4 memory layers concurrently, **so that** every LLM call starts with full context in <50ms.

**Acceptance Criteria**:
- [ ] `interceptor_jit_hydration(task_payload: dict) -> dict` — returns payload with `system_injection` field added
- [ ] Calls `fast_extract(task_payload)` → `(target_entities, intent_string)`
- [ ] Launches 3 concurrent futures: Redis L1, KG 1-hop, Qdrant top-2
- [ ] All 3 futures have 45ms timeout (not 50ms — leaves 5ms buffer)
- [ ] On timeout: uses empty/default value (graceful degradation, not failure)
- [ ] Assembles `<ZERO_AMNESIA_STATE>` XML envelope
- [ ] Attaches as `task_payload["system_injection"]`
- [ ] Returns enriched payload

**Implementation Skeleton**:
```python
import asyncio
from .fast_extract import fast_extract
from .scatter_gather import scatter_gather_memory
from .zero_amnesia_envelope import build_envelope

async def interceptor_jit_hydration(task_payload: dict) -> dict:
    target_entities, intent_string = fast_extract(task_payload)
    memory_context = await scatter_gather_memory(
        task_id=task_payload["task_id"],
        target_entities=target_entities,
        intent_string=intent_string,
        timeout_ms=45
    )
    envelope = build_envelope(memory_context)
    task_payload["system_injection"] = envelope
    return task_payload
```

**Test Plan**:
- BB: After hydration, `task_payload["system_injection"]` present and contains `<ZERO_AMNESIA_STATE>`
- BB: On Redis timeout → hydration still completes (graceful degradation)
- BB: Cold start (no Redis state) → `<WORKING_CONTEXT>Cold start. No prior state.</WORKING_CONTEXT>`
- WB: All 3 scatter futures launched concurrently (asyncio.gather)
- WB: Timeout enforced at 45ms, not 50ms

**Budget**: 7 implement + 4 BB + 3 WB + 1 IT + 1 stamp = 16 iterations

---

### Story 2.03: fast_extract() — Entity + Intent Extraction
**File**: `core/memory/fast_extract.py`

- **As** the JIT hydration system, **I need** a fast, deterministic entity and intent extractor that runs before any LLM call, **so that** I know which KG entities and Qdrant scars to fetch without spending context window on classification.

**Acceptance Criteria**:
- [ ] `fast_extract(task_payload: dict) -> tuple[list[str], str]`
- [ ] Returns `(target_entities, intent_string)` — both always populated (empty list/string for cold start)
- [ ] Entity extraction: regex patterns + keyword matching (NO LLM call)
- [ ] Intent extraction: first 200 chars of task `prompt` or `description` field
- [ ] Recognizes common entity types: file paths, function names, service names, session IDs
- [ ] File path regex: `r'[A-Za-z_][A-Za-z0-9_/\.]+\.(py|ts|js|json|md)'`
- [ ] Function name regex: `r'def\s+\w+|class\s+\w+'` in code snippets
- [ ] Gracefully handles missing fields (no KeyError)
- [ ] Pure Python, zero I/O, runs in <1ms

**Test Plan**:
- BB: Python file path in prompt → extracted as entity
- BB: No recognizable entities → returns `([], "")`
- BB: `fast_extract({})` → no exception, returns `([], "")`
- WB: No LLM calls made (mock time: <5ms)
- WB: Intent string capped at 200 chars

**Budget**: 5 implement + 3 BB + 3 WB + 1 IT + 1 stamp = 13 iterations

---

### Story 2.04: scatter_gather_memory() — Concurrent 3-Layer Fetch
**File**: `core/memory/scatter_gather.py`

- **As** the JIT hydration assembler, **I need** a concurrent scatter-gather that fetches L1 (Redis), L2 (KG), and L3 (Qdrant) memory in parallel, **so that** the total hydration latency is the max of the 3 individual fetches, not their sum.

**Acceptance Criteria**:
- [ ] `scatter_gather_memory(task_id, target_entities, intent_string, timeout_ms=45) -> MemoryContext`
- [ ] `MemoryContext` dataclass: `working_state: Optional[str]`, `kg_topology: Optional[str]`, `learned_constraints: Optional[str]`, `latency_ms: float`
- [ ] Uses `asyncio.gather(*tasks, return_exceptions=True)` for parallel fetch
- [ ] Each fetch has individual `asyncio.wait_for(timeout=timeout_ms/1000)` guard
- [ ] On any individual fetch exception → that field gets `None` (partial result is valid)
- [ ] KG fetch: reads relevant `KNOWLEDGE_GRAPH/entities/` jsonl file for entity match
- [ ] Qdrant fetch: semantic similarity search, top-2 results formatted as text
- [ ] Records total latency in `MemoryContext.latency_ms`

**Implementation Skeleton**:
```python
@dataclass
class MemoryContext:
    working_state: Optional[str]
    kg_topology: Optional[str]
    learned_constraints: Optional[str]
    latency_ms: float

async def scatter_gather_memory(task_id, target_entities, intent_string, timeout_ms=45) -> MemoryContext:
    start = time.monotonic()
    results = await asyncio.gather(
        asyncio.wait_for(_fetch_redis_l1(task_id), timeout=timeout_ms/1000),
        asyncio.wait_for(_fetch_kg_l2(target_entities), timeout=timeout_ms/1000),
        asyncio.wait_for(_fetch_qdrant_l3(intent_string), timeout=timeout_ms/1000),
        return_exceptions=True
    )
    latency = (time.monotonic() - start) * 1000
    working_state = results[0] if not isinstance(results[0], Exception) else None
    kg_topology = results[1] if not isinstance(results[1], Exception) else None
    learned_constraints = results[2] if not isinstance(results[2], Exception) else None
    return MemoryContext(working_state, kg_topology, learned_constraints, latency)
```

**Test Plan**:
- BB: All 3 fetches succeed → all 3 fields populated
- BB: Redis times out → `working_state=None`, other fields populated
- BB: All 3 time out → all fields None, latency_ms still recorded
- WB: `asyncio.gather` called once (not 3 sequential awaits)
- WB: Each fetch wrapped in `asyncio.wait_for` (individual timeout enforcement)

**Budget**: 7 implement + 4 BB + 3 WB + 1 IT + 1 stamp = 16 iterations

---

### Story 2.05: build_envelope() — ZERO_AMNESIA_STATE XML Assembly
**File**: `core/memory/zero_amnesia_envelope.py`

- **As** the LLM injection system, **I need** a function that assembles the `<ZERO_AMNESIA_STATE>` XML envelope from a `MemoryContext`, **so that** every LLM system prompt is augmented with the exact memory structure defined in the architecture spec.

**Acceptance Criteria**:
- [ ] `build_envelope(context: MemoryContext) -> str`
- [ ] Returns strict XML string (validated XML structure)
- [ ] Template from architecture spec:
  ```xml
  <ZERO_AMNESIA_STATE>
    <WORKING_CONTEXT>{working_state or "Cold start. No prior state."}</WORKING_CONTEXT>
    <TOPOLOGICAL_BLAST_RADIUS>{kg_topology or "No KG context available."}</TOPOLOGICAL_BLAST_RADIUS>
    <LEARNED_CONSTRAINTS>{learned_constraints or "No prior scars for this task type."}</LEARNED_CONSTRAINTS>
    <HYDRATION_LATENCY_MS>{context.latency_ms:.1f}</HYDRATION_LATENCY_MS>
  </ZERO_AMNESIA_STATE>
  ```
- [ ] All None fields replaced with canonical fallback strings
- [ ] Output parseable by `xml.etree.ElementTree.fromstring()`
- [ ] Escapes XML special characters in content fields (`<`, `>`, `&`, `"`)

**Test Plan**:
- BB: All fields None → fallback strings appear in output
- BB: Output passes `xml.etree.ElementTree.fromstring()` validation
- BB: Content with `<` character → escaped as `<`
- WB: `latency_ms` formatted to 1 decimal place
- WB: 4 XML tags always present regardless of None fields

**Budget**: 4 implement + 4 BB + 2 WB + 1 IT + 1 stamp = 13 iterations

---

### Story 2.06: JITHydrationInterceptor — Wires Hydration Into Chain
**File**: `core/memory/jit_hydration_interceptor.py`

- **As** the InterceptorChain, **I need** a concrete interceptor that wraps `interceptor_jit_hydration()` as a chain-compatible `BaseInterceptor`, **so that** memory injection is part of the standard pipeline without custom dispatch logic.

**Acceptance Criteria**:
- [ ] `JITHydrationInterceptor` extends `BaseInterceptor`
- [ ] `metadata = InterceptorMetadata(name="jit_hydration", priority=10)` — runs after telemetry (0), before business logic (50+)
- [ ] `pre_execute`: calls `interceptor_jit_hydration(task_payload)`, returns enriched payload
- [ ] `post_execute`: writes `system_injection` length to telemetry log
- [ ] `on_error`: returns payload with `system_injection = "<ZERO_AMNESIA_STATE><ERROR>Hydration failed</ERROR></ZERO_AMNESIA_STATE>"`
- [ ] `on_correction`: prepends "CORRECTION: " to prompt field and re-hydrates
- [ ] Auto-registered in `core/interceptors/__init__.py` startup

**Test Plan**:
- BB: After `pre_execute`, payload has `system_injection` with `<ZERO_AMNESIA_STATE>` tag
- BB: On hydration error → payload still has `system_injection` with error tag
- BB: `on_correction` payload has "CORRECTION: " prefix in prompt
- WB: Priority=10 places it between telemetry (0) and business interceptors (50+)
- WB: `post_execute` does not mutate the result dict

**Budget**: 5 implement + 3 BB + 3 WB + 1 IT + 1 stamp = 13 iterations

---

### Story 2.07 + 2.08: Test Suites — Module 2
**Files**: `tests/memory/test_redis_l1_schema.py` + `tests/memory/test_jit_hydration.py`

- **As** the Genesis test suite, **I need** BB + WB tests for the full JIT hydration pipeline (Redis L1, scatter-gather, envelope builder, and JIT interceptor), **so that** the zero-amnesia contract is continuously verified.

**Acceptance Criteria (2.07 — BB)**:
- [ ] Redis L1: set/get round-trip, cold-start None, key format
- [ ] Scatter-gather: all-success, partial timeout, total timeout
- [ ] Envelope builder: XML validation, fallback strings, special char escaping
- [ ] 12+ BB test cases

**Acceptance Criteria (2.08 — WB)**:
- [ ] `fast_extract` timing < 5ms assertion
- [ ] `asyncio.gather` called exactly once in scatter_gather
- [ ] Interceptor priority = 10 verified
- [ ] 10+ WB test cases

**Budget (each)**: 6 implement + 1 run + 1 fix + 1 re-run + 1 stamp = 10 iterations each

---


Successfully appended to E:\genesis-system\docs\plans\GENESIS_PERSISTENT_CONTEXT_ARCHITECTURE_PRD.md (282 lines) ✅ File written successfully! (282 lines)

💡 Performance tip: For optimal speed, consider chunking files into ≤30 line pieces in future operations.


## MODULE 3: MVFL Error-Correction Trap + Voyager Defense
**Q2 Implementation — Architecturally Forced Self-Correction**
**Stories**: 7 | **Estimate**: 4-5 days | **Wave**: 1 (fires simultaneously with Modules 1 & 2)

**Module Vision**: The system is architecturally forced to correct its own errors — not prompted to do so. Three trigger conditions (syntax error, semantic inconsistency, external rejection) each activate the MVFL loop. The Voyager Defense scores outputs against known failure patterns. MemGPT Pruning escalates to Opus after 3 failed correction attempts. The LLM cannot "choose" to skip correction — the interceptor makes it impossible.

**Module File Map**:
```
core/mvfl/mvfl_trigger.py                   ← Story 3.01
core/mvfl/voyager_defense.py                ← Story 3.02
core/mvfl/output_validator.py               ← Story 3.03
core/mvfl/correction_loop.py                ← Story 3.04
core/mvfl/memgpt_escalation.py              ← Story 3.05
core/mvfl/mvfl_interceptor.py               ← Story 3.06
tests/mvfl/test_mvfl_pipeline.py            ← Story 3.07
```

---

### Story 3.01: MVFLTrigger — 3-Condition Detection
**File**: `core/mvfl/mvfl_trigger.py`

- **As** the MVFL error-correction system, **I need** a trigger detector that evaluates any swarm output against 3 trigger conditions, **so that** errors are caught deterministically before release.

**Acceptance Criteria**:
- [ ] `MVFLTrigger` class with `evaluate(output: dict, task_payload: dict) -> MVFLTriggerResult`
- [ ] `MVFLTriggerResult` dataclass: `triggered: bool`, `trigger_type: Optional[str]`, `severity: int` (1-3), `details: str`
- [ ] **Condition 1 — Syntax/Format**: checks output against expected format schema; detects missing required fields, invalid JSON, type mismatches
- [ ] **Condition 2 — Semantic Inconsistency**: checks for internal contradictions in multi-field output (e.g., `status: "completed"` but `result: None`)
- [ ] **Condition 3 — External Rejection**: checks `output.get("status_code")` for 4xx/5xx HTTP codes or `output.get("api_error")` present
- [ ] Returns first triggered condition (priority: Condition 3 > 2 > 1)
- [ ] Returns `triggered=False` if no condition met

**Implementation Skeleton**:
```python
@dataclass
class MVFLTriggerResult:
    triggered: bool
    trigger_type: Optional[str]  # "syntax" | "semantic" | "external_rejection"
    severity: int  # 1=warning, 2=error, 3=critical
    details: str

class MVFLTrigger:
    def evaluate(self, output: dict, task_payload: dict) -> MVFLTriggerResult:
        # Check external rejection first (highest priority)
        if self._check_external_rejection(output):
            return MVFLTriggerResult(True, "external_rejection", 3, ...)
        # Then semantic
        if self._check_semantic_inconsistency(output, task_payload):
            return MVFLTriggerResult(True, "semantic", 2, ...)
        # Then syntax
        if self._check_syntax_errors(output, task_payload):
            return MVFLTriggerResult(True, "syntax", 1, ...)
        return MVFLTriggerResult(False, None, 0, "Clean output")
```

**Test Plan**:
- BB: Output with `status_code: 422` → triggers external_rejection severity 3
- BB: Output with `status: "completed"` and `result: None` → triggers semantic severity 2
- BB: Clean output → `triggered=False`
- WB: Condition 3 takes priority over Condition 2 (both present → external_rejection returned)
- WB: `MVFLTriggerResult.trigger_type` is None when `triggered=False`

**Budget**: 6 implement + 4 BB + 3 WB + 1 IT + 1 stamp = 15 iterations

---

### Story 3.02: VoyagerDefense — Scar-Pattern Scorer
**File**: `core/mvfl/voyager_defense.py`

- **As** the pre-release quality gate, **I need** a Voyager Defense scorer that compares output against known failure patterns in Qdrant L3, **so that** historically-failed output shapes are caught before release even if no current trigger fires.

**Acceptance Criteria**:
- [ ] `VoyagerDefense` class with `score(output: dict) -> VoyagerScore`
- [ ] `VoyagerScore` dataclass: `score: float` (0.0-1.0, higher = riskier), `matched_scars: list[str]`, `should_block: bool`
- [ ] `should_block = score >= BLOCK_THRESHOLD` (default `BLOCK_THRESHOLD = 0.7`)
- [ ] Queries Qdrant L3 collection `genesis_scars` with output embedding
- [ ] Returns top-3 similar scars as `matched_scars` list of IDs
- [ ] On Qdrant unavailable → returns `VoyagerScore(0.0, [], False)` (fail open, not closed)
- [ ] `BLOCK_THRESHOLD` configurable via `VOYAGER_BLOCK_THRESHOLD` env variable
- [ ] Scoring formula: `max(similarity_scores[:3])` — worst-case scar similarity

**Test Plan**:
- BB: Output matching a known bad pattern → `score >= 0.7, should_block=True`
- BB: Qdrant unavailable → returns `score=0.0, should_block=False` (fail open)
- BB: Clean output with no matching scars → `score < 0.7, should_block=False`
- WB: Qdrant query uses semantic similarity (not keyword match)
- WB: `BLOCK_THRESHOLD` reads from env variable

**Budget**: 6 implement + 4 BB + 3 WB + 1 IT + 1 stamp = 15 iterations

---

### Story 3.03: OutputValidator — Format + Type Schema Checker
**File**: `core/mvfl/output_validator.py`

- **As** the MVFL syntax checker, **I need** a typed schema validator for swarm output, **so that** format errors (missing fields, wrong types, empty required strings) are caught before Voyager Defense runs.

**Acceptance Criteria**:
- [ ] `OutputValidator` class with `validate(output: dict, schema: dict) -> ValidationResult`
- [ ] `ValidationResult` dataclass: `valid: bool`, `errors: list[str]`
- [ ] Schema format: `{"field_name": {"type": "str|int|float|list|dict|bool", "required": True/False}}`
- [ ] Type checking validates Python type against schema type
- [ ] `required: True` fields that are None or missing → error added
- [ ] Empty string for required str field → error added
- [ ] Returns all errors (not fail-fast on first error)
- [ ] `DEFAULT_SWARM_OUTPUT_SCHEMA` defined in module (covers standard dispatch_to_swarm output)

**Test Plan**:
- BB: Missing required field → error in `ValidationResult.errors`
- BB: Wrong type → error message includes expected type vs actual type
- BB: Valid output → `valid=True, errors=[]`
- WB: All errors collected before returning (not fail-fast)
- WB: `DEFAULT_SWARM_OUTPUT_SCHEMA` has at minimum `task_id` and `status` fields

**Budget**: 5 implement + 3 BB + 3 WB + 1 IT + 1 stamp = 13 iterations

---

### Story 3.04: CorrectionLoop — MVFL Re-injection Engine
**File**: `core/mvfl/correction_loop.py`

- **As** the MVFL self-correction system, **I need** a correction loop that re-injects failed output back to the LLM with a `CORRECTION:` prefixed prompt and tracks attempt count, **so that** errors trigger automatic retry up to 3 times before escalation.

**Acceptance Criteria**:
- [ ] `CorrectionLoop` class with `run(task_payload: dict, failed_output: dict, trigger: MVFLTriggerResult) -> CorrectionResult`
- [ ] `CorrectionResult` dataclass: `success: bool`, `output: dict`, `attempts: int`, `escalated: bool`
- [ ] Max 3 correction attempts before escalation
- [ ] Each attempt: prepends `"CORRECTION: [trigger.details]\n\n"` to `task_payload["prompt"]`
- [ ] Re-dispatches through `dispatch_to_swarm()` (same chain — including JIT hydration)
- [ ] Each attempt: re-evaluates with `MVFLTrigger` and `VoyagerDefense`
- [ ] On clean output: returns `CorrectionResult(success=True, output=..., attempts=n, escalated=False)`
- [ ] After 3 failed attempts: calls `MemGPTEscalation.escalate()`, returns `escalated=True`

**Implementation Skeleton**:
```python
MAX_CORRECTION_ATTEMPTS = 3

class CorrectionLoop:
    async def run(self, task_payload, failed_output, trigger) -> CorrectionResult:
        for attempt in range(1, MAX_CORRECTION_ATTEMPTS + 1):
            correction_prompt = f"CORRECTION: {trigger.details}\n\n{task_payload['prompt']}"
            corrected_payload = {**task_payload, "prompt": correction_prompt, "attempt": attempt}
            output = await dispatch_to_swarm(corrected_payload)
            new_trigger = self.trigger.evaluate(output, corrected_payload)
            voyager = self.voyager.score(output)
            if not new_trigger.triggered and not voyager.should_block:
                return CorrectionResult(True, output, attempt, False)
        # All attempts exhausted
        escalated_output = await self.escalation.escalate(task_payload, failed_output)
        return CorrectionResult(False, escalated_output, MAX_CORRECTION_ATTEMPTS, True)
```

**Test Plan**:
- BB: Bad output → corrected on attempt 2 → `success=True, attempts=2, escalated=False`
- BB: 3 failed attempts → `escalated=True`
- BB: Correction prompt always starts with "CORRECTION: "
- WB: `MAX_CORRECTION_ATTEMPTS` constant controls loop limit
- WB: Each correction attempt re-runs JIT hydration via dispatch_to_swarm

**Budget**: 7 implement + 4 BB + 3 WB + 1 IT + 1 stamp = 16 iterations

---

### Story 3.05: MemGPTEscalation — Opus Escalation on 3-Strike
**File**: `core/mvfl/memgpt_escalation.py`

- **As** the MVFL maximum-effort fallback, **I need** an Opus escalation handler that receives the full failure history and re-attempts with maximum reasoning model, **so that** tasks that stump Gemini Flash are resolved by Opus with full context.

**Acceptance Criteria**:
- [ ] `MemGPTEscalation` class with `escalate(task_payload: dict, failed_output: dict) -> dict`
- [ ] Builds escalation context: original task + all 3 failed attempt outputs + MVFL trigger details
- [ ] Dispatches to Opus 4.6 (not Gemini Flash) via `ESCALATION_MODEL = "claude-opus-4-6"`
- [ ] Escalation system prompt: `"You are the Genesis Maximum-Effort Resolver. Previous agents have failed 3 times. Full failure history:\n{failure_history}\n\nResolve this definitively."`
- [ ] Records escalation event to `data/observability/events.jsonl` with `event: "mvfl_escalation"`
- [ ] Returns Opus response as standard output dict
- [ ] On Opus failure → returns `{"status": "error", "error": "MVFL_ESCALATION_FAILED", "task_id": ...}`

**Test Plan**:
- BB: Escalation builds prompt with all 3 failure details
- BB: Escalation uses `ESCALATION_MODEL = "claude-opus-4-6"` (not Flash)
- BB: Escalation event written to events.jsonl
- WB: Failure history includes trigger_type and details from all 3 attempts
- WB: On Opus failure → returns error dict with `MVFL_ESCALATION_FAILED` code

**Budget**: 6 implement + 3 BB + 3 WB + 1 IT + 1 stamp = 14 iterations

---

### Story 3.06: MVFLInterceptor — Wires MVFL Into Chain
**File**: `core/mvfl/mvfl_interceptor.py`

- **As** the InterceptorChain, **I need** a concrete interceptor that wires the MVFL pipeline (trigger → voyager → correction loop) as a `BaseInterceptor`, **so that** error correction fires automatically on every task result.

**Acceptance Criteria**:
- [ ] `MVFLInterceptor` extends `BaseInterceptor`
- [ ] `metadata = InterceptorMetadata(name="mvfl", priority=90)` — runs late in chain, after business logic
- [ ] `pre_execute`: no-op (passes through unchanged)
- [ ] `post_execute`: runs MVFLTrigger.evaluate + VoyagerDefense.score; if triggered → runs CorrectionLoop and REPLACES result in Redis (side-effect)
- [ ] `on_error`: same as post_execute but with error context
- [ ] `on_correction`: passthrough (correction handling is inside CorrectionLoop)
- [ ] Records MVFL decision (blocked/passed) to events.jsonl

**Test Plan**:
- BB: Clean output → post_execute passes through unchanged
- BB: Triggered output → CorrectionLoop called, corrected output written to Redis
- BB: MVFL intercept recorded in events.jsonl
- WB: Priority=90 ensures MVFL runs after JIT hydration (10) and business logic
- WB: `pre_execute` truly returns unchanged payload

**Budget**: 5 implement + 3 BB + 3 WB + 1 IT + 1 stamp = 13 iterations

---

### Story 3.07: Test Suite — Module 3 MVFL Pipeline
**File**: `tests/mvfl/test_mvfl_pipeline.py`

- **As** the Genesis test suite, **I need** full BB + WB tests for the complete MVFL pipeline, **so that** self-correction behavior is continuously verified end-to-end.

**Acceptance Criteria**:
- [ ] BB: syntax error → trigger fires → correction loop runs → clean output returned
- [ ] BB: Qdrant scar match → Voyager blocks → escalation fires
- [ ] BB: 3-strike → escalation to Opus confirmed
- [ ] WB: MVFLTrigger condition priority verified (external > semantic > syntax)
- [ ] WB: CorrectionLoop max attempts constant = 3
- [ ] 15+ total test cases
- [ ] All mocked (no live Qdrant, no live Opus calls)

**Budget**: 7 implement + 1 run + 1 fix + 1 re-run + 1 stamp = 11 iterations

---


Successfully appended to E:\genesis-system\docs\plans\GENESIS_PERSISTENT_CONTEXT_ARCHITECTURE_PRD.md (233 lines) ✅ File written successfully! (233 lines)

💡 Performance tip: For optimal speed, consider chunking files into ≤30 line pieces in future operations.


## MODULE 4: 80/20 Tier Router + Strangler Fig Migration
**Q3 Implementation — Synchronous Interceptor Pipeline**
**Stories**: 7 | **Estimate**: 4-5 days | **Wave**: 2 (after Module 1 complete)

**Module Vision**: 80% of Genesis tasks don't need LLM reasoning. Route them deterministically and save the Opus context window for the 20% that do. The `TierRouter` classifies every task before dispatch. The Strangler Fig wrapper progressively replaces every direct tool call with `dispatch_to_swarm()` — consuming the legacy pattern one wrapper at a time.

**Module File Map**:
```
core/routing/tier_router.py                 ← Story 4.01
core/routing/tier_classifier.py             ← Story 4.02
core/routing/tier_executor.py               ← Story 4.03
core/routing/strangler_fig.py               ← Story 4.04
core/routing/routing_telemetry.py           ← Story 4.05
core/routing/tier_router_interceptor.py     ← Story 4.06
tests/routing/test_tier_router.py           ← Story 4.07
```

---

### Story 4.01: TierRouter — Task Classification Router
**File**: `core/routing/tier_router.py`

- **As** the dispatch system, **I need** a tier router that classifies every task into Tier 0 (deterministic), Tier 1 (parametric), or Tier 2 (reasoning) before any LLM call, **so that** 80% of tasks bypass expensive reasoning models.

**Acceptance Criteria**:
- [ ] `TierRouter` class with `route(task_payload: dict) -> RoutingDecision`
- [ ] `RoutingDecision` dataclass: `tier: str` ("T0"|"T1"|"T2"), `model: str`, `rationale: str`, `is_cached: bool`
- [ ] **Tier 0 (Deterministic)**: simple CRUD/lookups/format-transforms → `model="python_function"`, no LLM
- [ ] **Tier 1 (Parametric)**: template-driven with known structure → `model="gemini-flash"`, fast Gemini call
- [ ] **Tier 2 (Reasoning)**: novel decisions, contradictions, planning → `model="claude-opus-4-6"`
- [ ] Classification uses `TierClassifier.classify(task_payload)` (Story 4.02)
- [ ] Result cached in Redis: `genesis:routing:{hash(task_type)}` with 300s TTL (same task type = same tier)
- [ ] Records `{task_id, tier, model, rationale}` to events.jsonl

**Implementation Skeleton**:
```python
class TierRouter:
    def route(self, task_payload: dict) -> RoutingDecision:
        task_type = task_payload.get("type", "unknown")
        cache_key = f"genesis:routing:{hash(task_type)}"
        cached = self.redis.get(cache_key)
        if cached:
            return RoutingDecision(**json.loads(cached), is_cached=True)
        decision = self.classifier.classify(task_payload)
        self.redis.setex(cache_key, 300, json.dumps(asdict(decision)))
        return decision
```

**Test Plan**:
- BB: CRUD task → Tier 0, model="python_function"
- BB: Template task → Tier 1, model="gemini-flash"
- BB: Same task type called twice → second call is_cached=True
- WB: Cache key uses `hash(task_type)` not full payload hash
- WB: `events.jsonl` entry written on every routing decision

**Budget**: 6 implement + 4 BB + 3 WB + 1 IT + 1 stamp = 15 iterations

---

### Story 4.02: TierClassifier — Heuristic Task Classifier
**File**: `core/routing/tier_classifier.py`

- **As** the TierRouter, **I need** a heuristic classifier that uses task type, payload shape, and keyword patterns to determine tier, **so that** classification costs zero LLM tokens.

**Acceptance Criteria**:
- [ ] `TierClassifier` class with `classify(task_payload: dict) -> RoutingDecision`
- [ ] **T0 triggers** (any match → T0): `task_payload["type"]` in T0_TYPES, payload has `"crud_operation"` key, payload has `"lookup_key"` key
- [ ] `T0_TYPES = {"health_check", "redis_read", "redis_write", "kg_lookup", "format_transform", "log_event"}`
- [ ] **T1 triggers** (any match → T1): payload has `"template"` key, `task_payload["type"]` in T1_TYPES
- [ ] `T1_TYPES = {"email_draft", "faq_answer", "lead_qualify", "status_update"}`
- [ ] **T2 default**: anything not matching T0 or T1
- [ ] Returns `RoutingDecision` with rationale string explaining which rule triggered
- [ ] No LLM calls — pure Python heuristics

**Test Plan**:
- BB: `type="health_check"` → T0
- BB: `type="lead_qualify"` → T1
- BB: `type="novel_decision"` → T2 (default)
- WB: T0 check runs before T1 check (priority ordering)
- WB: Rationale string identifies which rule triggered

**Budget**: 5 implement + 3 BB + 3 WB + 1 IT + 1 stamp = 13 iterations

---

### Story 4.03: TierExecutor — Tier-Appropriate Dispatcher
**File**: `core/routing/tier_executor.py`

- **As** the routing system, **I need** a tier executor that dispatches tasks to the correct execution path based on their `RoutingDecision`, **so that** Tier 0 tasks never touch an LLM and Tier 2 tasks always reach Opus.

**Acceptance Criteria**:
- [ ] `TierExecutor` class with `execute(task_payload: dict, decision: RoutingDecision) -> dict`
- [ ] **T0 path**: routes to `T0_HANDLER_REGISTRY[task_type](task_payload)` — pure Python functions
- [ ] **T1 path**: builds parametric prompt from `task_payload["template"]`, calls Gemini Flash API
- [ ] **T2 path**: builds full reasoning prompt, calls Opus via `dispatch_to_swarm()` (recursive — but with tier="T2" guard to prevent re-classification)
- [ ] `T0_HANDLER_REGISTRY` is a dict: `{task_type: Callable}` — importable registry
- [ ] On missing T0 handler: falls back to T1 path (graceful degradation)
- [ ] Returns standard `{"task_id", "tier", "model", "output", "status"}` dict

**Test Plan**:
- BB: T0 task with registered handler → Python function called, no LLM
- BB: T0 task without handler → falls back to T1
- BB: T2 task → Opus model used
- WB: T2 path adds `tier="T2"` guard to prevent re-classification loop
- WB: T0_HANDLER_REGISTRY is accessible as module-level dict

**Budget**: 6 implement + 3 BB + 3 WB + 1 IT + 1 stamp = 14 iterations

---

### Story 4.04: StranglerFig — Progressive Migration Wrapper
**File**: `core/routing/strangler_fig.py`

- **As** the Strangler Fig migration system, **I need** a wrapper decorator that wraps any existing direct function call with `dispatch_to_swarm()`, **so that** we progressively add interceptor coverage without rewriting existing code.

**Acceptance Criteria**:
- [ ] `strangler_fig(task_type: str, tier: Optional[str] = None)` — Python decorator
- [ ] Wraps any async function: the wrapped function's output passes through the interceptor chain
- [ ] Adds `task_type` and `tier` to `task_payload` before dispatch
- [ ] Original function's args → converted to `task_payload["args"]`
- [ ] Original function's return value → stored as `task_payload["original_result"]`
- [ ] If `dispatch_to_swarm` is unavailable → falls back to original function (fail-safe)
- [ ] `@strangler_fig("ghl_lead_capture", tier="T1")` syntax works as decorator
- [ ] Migration registry: `WRAPPED_FUNCTIONS` dict logs all wrapped functions on module import

**Implementation Skeleton**:
```python
WRAPPED_FUNCTIONS = {}

def strangler_fig(task_type: str, tier: Optional[str] = None):
    def decorator(func):
        WRAPPED_FUNCTIONS[func.__name__] = {"task_type": task_type, "tier": tier}
        @functools.wraps(func)
        async def wrapper(*args, **kwargs):
            original_result = await func(*args, **kwargs)
            task_payload = {
                "type": task_type,
                "tier": tier,
                "args": args,
                "kwargs": kwargs,
                "original_result": original_result
            }
            try:
                return await dispatch_to_swarm(task_payload)
            except Exception:
                return original_result  # Fail-safe fallback
        return wrapper
    return decorator
```

**Test Plan**:
- BB: `@strangler_fig("test_type")` wraps function → intercept chain fires
- BB: dispatch_to_swarm unavailable → original function result returned
- BB: `WRAPPED_FUNCTIONS` registry updated on decoration
- WB: `functools.wraps` preserves original function name/docstring
- WB: Fail-safe catches exception from dispatch_to_swarm (not from original func)

**Budget**: 6 implement + 4 BB + 3 WB + 1 IT + 1 stamp = 15 iterations

---

### Story 4.05: RoutingTelemetry — Tier Distribution Analytics
**File**: `core/routing/routing_telemetry.py`

- **As** the Genesis observability layer, **I need** routing telemetry that tracks tier distribution over time, **so that** we can verify the 75% T0/T1 target and identify T2 tasks that could be downtier'd.

**Acceptance Criteria**:
- [ ] `RoutingTelemetry` class with `record(decision: RoutingDecision)` and `get_distribution() -> dict`
- [ ] Counters stored in Redis: `genesis:routing:stats:t0_count`, `t1_count`, `t2_count`
- [ ] `get_distribution()` returns `{"t0": n, "t1": n, "t2": n, "t0_t1_pct": float}`
- [ ] `t0_t1_pct = (t0 + t1) / (t0 + t1 + t2) * 100` — the 75% target metric
- [ ] `log_tier_report()` — writes current distribution to events.jsonl
- [ ] Redis counters use INCR (atomic, no race conditions)
- [ ] Counters persist across sessions (no TTL — cumulative stats)

**Test Plan**:
- BB: Record 8 T0, 2 T1, 2 T2 → `t0_t1_pct = 83.3%`
- BB: `get_distribution()` reflects recorded counts
- BB: `log_tier_report()` writes JSON entry to events.jsonl
- WB: Counters use Redis INCR (not SET)
- WB: No TTL on counter keys (persists across sessions)

**Budget**: 5 implement + 3 BB + 3 WB + 1 IT + 1 stamp = 13 iterations

---

### Story 4.06: TierRouterInterceptor — Wires Routing Into Chain
**File**: `core/routing/tier_router_interceptor.py`

- **As** the InterceptorChain, **I need** a `TierRouterInterceptor` that classifies every task and sets `task_payload["tier"]` before it reaches the execution engine, **so that** execution always knows which model to use.

**Acceptance Criteria**:
- [ ] `TierRouterInterceptor` extends `BaseInterceptor`
- [ ] `metadata = InterceptorMetadata(name="tier_router", priority=20)` — after JIT hydration (10), before business (50+)
- [ ] `pre_execute`: calls `TierRouter.route(task_payload)`, sets `task_payload["tier"]` and `task_payload["model"]`
- [ ] `post_execute`: calls `RoutingTelemetry.record(decision)` (tracks distribution)
- [ ] `on_error`: defaults to T2/Opus (safer on routing failure)
- [ ] `on_correction`: no-op passthrough

**Test Plan**:
- BB: After pre_execute, payload has `tier` and `model` fields
- BB: Routing error → payload defaults to T2/Opus
- WB: Priority=20 runs after JIT hydration (10) and before business interceptors
- WB: RoutingTelemetry.record called in post_execute (not pre_execute)

**Budget**: 4 implement + 3 BB + 2 WB + 1 IT + 1 stamp = 11 iterations

---

### Story 4.07: Test Suite — Module 4 Routing
**File**: `tests/routing/test_tier_router.py`

**Acceptance Criteria**:
- [ ] BB: T0/T1/T2 classification for 10+ task types
- [ ] BB: Strangler Fig wraps and falls back safely
- [ ] BB: Distribution tracking accumulates correctly
- [ ] WB: T0 path has zero LLM calls
- [ ] WB: T2 path verifies Opus model selection
- [ ] 14+ total test cases

**Budget**: 6 implement + 1 run + 1 fix + 1 re-run + 1 stamp = 10 iterations

---


Successfully appended to E:\genesis-system\docs\plans\GENESIS_PERSISTENT_CONTEXT_ARCHITECTURE_PRD.md (225 lines) ✅ File written successfully! (225 lines)

💡 Performance tip: For optimal speed, consider chunking files into ≤30 line pieces in future operations.


Continuing — writing Modules 5, 6, 7 (CQRS, Coherence, SemanticMerge):