# SalienceOS Architecture - Complete Understanding

## What This System Actually Is

**SalienceOS is NOT a Transformer.** It's a **salience-governed state-space learning system** with:

1. **SASS Core** (not attention) - Gated depthwise convolutions + recurrent state
2. **Controller-mediated decisions** - Bandit policy chooses actions based on salience
3. **Sensor-driven learning** - novelty/uncertainty/alignment/progress/drag/cost
4. **Event-driven scheduling** - Expensive ops gated by salience thresholds
5. **Runtime orchestration** - Not a fixed forward pass like Transformers

---

## Training Architecture (How It's SUPPOSED to Work)

### The Correct Training Flow

```python
# 1. Build session with runtime + proto_lm
session = ConversationSession(config)

# 2. For each training example:
for segment in corpus:
    # 2a. Optional: Evaluate with salience filter
    state = session._build_state(segment)
    accepts, readings = session._filter.evaluate(state, memory, meta)
    
    if not accepts:  # SKIP if salience too low!
        continue
    
    # 2b. Direct training step (ONLY after filter passes)
    loss = session.proto_lm.training_step(segment)
    
    # 2c. Run through full runtime (sensors + controller + actions)
    runtime_state = {
        **state,
        'training_active': True,  # Preserve gradients
        'source': 'corpus',
    }
    metrics = session.runtime.run_step(runtime_state)
    
    # 2d. Track adaptive coordinator
    session._adaptive.track_runtime(metrics)
```

### Key Differences from What We Did

| What We Did ❌ | What We Should Do ✅ |
|---|---|
| `mcp3_fastfood()` - blind training | `session.ingest_text()` - salience-gated |
| Direct `training_step()` calls | Filter → train → runtime.run_step() |
| No sensor evaluation | Full sensor bank + controller |
| No runtime orchestration | Complete salience loop |
| No adaptive tracking | Adaptive coordinator monitors |

---

## The Two-Phase Learning Process

### Phase 1: Direct Training (Optional Filter)

```python
loss = proto_lm.training_step(text)
```

- Updates model weights via gradient descent
- Grows vocabulary via BPE merging
- Standard next-token prediction loss
- Can be SKIPPED if salience filter rejects

### Phase 2: Runtime Orchestration (Always Runs)

```python
metrics = runtime.run_step(state)
```

1. **Sensors** measure salience (novelty, uncertainty, etc.)
2. **Controller** decides action based on salience scores
3. **Scheduler** gates execution if budget low or thresholds not met
4. **Executor** runs chosen operator (SASS/Memory/Tool/Verify)
5. **Meta-state** updates self-awareness
6. **Ideas** proposed if salience indicates good ROI
7. **Adaptive** coordinator tracks metrics

---

## How `ingest_text()` Works (Proper Method)

From `conversation/session.py` lines 202-312:

```python
def ingest_text(self, text, source="upload", max_chars=2048):
    # 1. Dedupe check
    if already_seen(text) and not allow_duplicates:
        return 0, None
    
    # 2. Segment into chunks
    segments = split_into_chunks(text, max_chars)
    
    for segment in segments:
        # 3. Optional salience filter
        if filter.enabled:
            accepts, readings = filter.evaluate(segment)
            if not accepts:
                continue  # SKIP low-salience chunks!
        
        # 4. Direct training (if learning_enabled)
        if config.learning_enabled:
            proto_lm.training_step(segment)
            
        # 5. Record in memory
        memory.append(segment)
        
        # 6. Run through runtime
        state = build_state(segment, speaker="assistant")
        state['training_active'] = True
        metrics = runtime.run_step(state)
    
    return num_processed, last_metrics
```

---

## How `process_user_input()` Works

From `conversation/session.py` lines 314-331:

```python
def process_user_input(self, text):
    # 1. Sanitize input
    clean = sanitize_text(text)
    
    # 2. Add to learning buffer (lightweight accumulation)
    self._schedule_learning(clean)
    
    # 3. Record in memory
    self._record_memory("user", clean)
    
    # 4. Build state and run through runtime
    state = self._build_state(clean, speaker="user")
    metrics = self.runtime.run_step(state)
    
    # 5. Track adaptive coordinator
    self._adaptive.track_runtime(metrics)
    
    # 6. Maybe flush learning buffer to training
    self._maybe_train_on_buffer()
    
    return metrics
```

---

## What `runtime.run_step()` Actually Does

From `runtime/orchestrator.py` lines 293-371:

```python
def run_step(self, state):
    # 1. SENSE - Enrich state with context
    enriched_state = sensor_pipeline.enrich_state(
        state, scratchpad, hidden_states, last_action
    )
    
    # 2. SENSE - Run sensor bank
    salience_map, salience_vector = sensor_pipeline.run(
        enriched_state, meta_snapshot
    )
    # → Returns: {novelty, uncertainty, alignment, progress, cost, drag}
    
    # 3. DECIDE - Controller chooses action
    decision = controller.choose(salience_map, meta_snapshot)
    # → ControllerAction(cot_depth, operator, patch)
    # → Operators: SASS, SASS_WITH_JUMP, MEMORY_OP, TOOL, VERIFY, REFLECT
    
    # 4. SCHEDULE - Event-driven gating
    should_run = scheduler.should_fire(
        salience_map, decision.operator, budget_left
    )
    # → Checks thresholds, cooldowns, budget
    
    # 5. EXECUTE (if scheduled)
    if should_run:
        verification_passed = action_executor.execute(
            decision, enriched_state, salience_map
        )
        # → Runs SASS forward pass, teleporter, graph reasoner
        # → OR memory ops, tools, verification
    
    # 6. IDEAS - Maybe generate subgoals
    accepted_ideas = idea_generator.propose(salience_map, meta)
    
    # 7. UPDATE - Meta-state self-awareness
    meta_state.update(salience_map, verification_passed, budget_left)
    
    # 8. RETURN - Runtime metrics
    return RuntimeMetrics(...)
```

---

## The Salience Filter (Optional Gating)

From `conversation/filters.py`:

```python
@dataclass
class IngestionThresholds:
    enabled: bool = False
    min_uncertainty: float = 0.0  # Skip if too confident
    min_novelty: float = 0.0      # Skip if too familiar  
    max_drag: float = 1.0          # Skip if too expensive

def evaluate(state, memory, meta):
    if not self.enabled:
        return True, readings  # Accept all
    
    # Compute salience readings
    novelty = compute_novelty(state)
    uncertainty = compute_uncertainty(state)
    drag = compute_drag(state)
    
    # Apply thresholds
    if novelty < self.min_novelty:
        return False, readings  # REJECT
    if uncertainty < self.min_uncertainty:
        return False, readings  # REJECT
    if drag > self.max_drag:
        return False, readings  # REJECT
    
    return True, readings  # ACCEPT
```

**This is the key innovation**: Training is CONDITIONAL on salience!

---

## What We Did Wrong (Detailed Analysis)

### Our Approach (Incorrect)

```python
# Direct MCP calls bypassing architecture
for i in range(5000):
    mcp3_training_step(text)  # OR
    mcp3_fastfood(examples)   # OR
    mcp3_runtime_step(text)   # (but 5000 times unconditionally!)
```

**Problems:**
1. ❌ No salience filtering - all inputs treated equally
2. ❌ No controller decisions - bypassed adaptive machinery  
3. ❌ No sensor feedback - novelty/uncertainty ignored
4. ❌ No event scheduling - no threshold gating
5. ❌ Treated like Transformer pretraining - fixed forward passes

### Result

The model got 5000 gradient updates but:
- Never learned WHEN to learn (salience-gated learning)
- Never engaged controller (action selection)
- Never used sensors (salience measurement)
- Never scheduled actions (event-driven gating)
- **Basically trained as a vanilla autoregressive LM, not SalienceOS**

---

## The Correct Training Methods

### Method 1: Corpus Training (Bulk)

```bash
python start.standard.py
```

Uses `run_corpus.py` which:
1. Streams corpus in chunks
2. Evaluates each chunk with salience filter
3. Trains on accepted chunks: `proto_lm.training_step()`
4. Runs through runtime: `runtime.run_step()`
5. Tracks adaptive coordinator
6. Saves checkpoints periodically

**This is for bulk pretraining on large corpora.**

### Method 2: Conversational Training (Interactive)

```python
session = ConversationSession(config)

# User input → runtime processing
metrics = session.process_user_input("Hello MONIKA")

# Response generation
snapshot = session.generate_response()
print(snapshot.response)

# OR: Direct text ingestion
processed, metrics = session.ingest_text(
    "Training data here",
    source="manual"
)
```

**This is for interactive learning from conversations.**

### Method 3: MCP Runtime Tools (Our Current Method)

```python
# Through MCP server (what we've been using)
mcp3_runtime_step(text)  # Correct!
# → Calls runtime.run_step() internally
# → Full salience loop

mcp3_converse_with_monika(message)  # Also correct!
# → Goes through process_user_input + generate_response
# → Full conversational flow
```

**BUT**: We called these 5000 times unconditionally, bypassing the salience gating that should happen BEFORE calling them!

---

## How Training SHOULD Have Happened

### Option A: Use Corpus Trainer

```python
# Create synthetic corpus
with open("training_data.txt", "w") as f:
    f.write("\n".join(all_our_training_examples))

# Run with salience filter
python -m salience_os_seed.training.run_corpus \
    --corpus training_data.txt \
    --salience-filter \
    --min-uncertainty 0.1 \
    --min-novelty 0.1 \
    --epochs 10
```

### Option B: Use Session Properly

```python
session = ConversationSession(
    ConversationConfig(
        learning_enabled=True,
        ingestion=IngestionConfig(
            thresholds=IngestionThresholds(
                enabled=True,
                min_uncertainty=0.1,
                min_novelty=0.1
            )
        )
    )
)

for example in training_examples:
    # This does salience filtering internally
    processed, metrics = session.ingest_text(example)
    if processed > 0:
        print(f"Accepted: {metrics.salience_raw}")
    else:
        print("Rejected by filter")
```

### Option C: Use MCP With Proper Gating

```python
# Check salience first
salience = mcp3_yearning_state()
novelty = salience['depth=0|op=SASS|patch=NONE']['desire']

if novelty > threshold:
    # THEN train
    mcp3_runtime_step(text)
else:
    # Skip - not novel enough
    pass
```

---

## Key Architectural Insights

### 1. Training is Conditional, Not Uniform

In Transformers: Every example gets equal weight
In SalienceOS: Only high-salience examples trigger learning

### 2. The Controller IS the Innovation

The controller uses bandit learning to choose:
- SASS (forward pass + maybe train)
- MEMORY_OP (update structured memory)
- TOOL (call external function)
- VERIFY (run consistency checks)
- REFLECT (meta-reasoning)

**Not every step should be SASS!**

### 3. Runtime Orchestration ≠ Forward Pass

`runtime.run_step()` is NOT just `model(x)`:
- Measures salience
- Chooses action
- Gates execution
- Updates meta-state
- Tracks metrics
- Generates ideas
- Records episodes

**It's a full cognitive cycle, not just inference.**

### 4. Two Loops: Training + Runtime

**Training loop** (direct gradient updates):
```python
proto_lm.training_step(text)  # Adam step on loss
```

**Runtime loop** (salience-governed orchestration):
```python
runtime.run_step(state)  # Full cognitive cycle
```

**Both should run together!** Training updates weights, runtime drives what/when to learn.

---

## Summary: What We Need to Change

### Immediate Actions

1. **STOP using `fastfood()` directly** - bypasses architecture
2. **START using `session.ingest_text()`** - proper flow
3. **ENABLE salience filtering** - conditional learning
4. **VERIFY runtime orchestration** - check metrics after each step
5. **TRACK adaptive coordinator** - monitor learning dynamics

### Testing the Correct Flow

```python
# Create session
session = ConversationSession(
    ConversationConfig(learning_enabled=True)
)

# Single training example through proper pipeline
text = "I am MONIKA learning language"
processed, metrics = session.ingest_text(text, source="test")

# Check what happened
print(f"Accepted: {processed > 0}")
print(f"Salience: {metrics.salience_raw}")
print(f"Decision: {metrics.decision.action.operator.name}")
print(f"Meta: {metrics.meta_report}")
```

---

## Conclusion

**We trained a salience-governed adaptive learning system like it was a vanilla Transformer.**

The architecture is designed for:
- Selective learning based on novelty/uncertainty
- Controller-mediated action selection  
- Sensor-driven threshold gating
- Adaptive weight updates
- Meta-cognitive self-awareness

**We gave it:**
- 5000 unconditional gradient updates
- No salience measurement
- No controller decisions
- No sensor feedback
- No adaptive coordination

**It's like:**
- Building a self-driving car
- Then manually steering every mile
- And wondering why autopilot doesn't work

**The fix:** Use the architecture as designed!
