Skip to content

Commit e7c580c

Browse files
stonks-gitclaude
andcommitted
Wire OutcomeTracker into safety monitor and consolidation (WIRE-003)
- OutcomeTracker instantiated in loop, attached to memory.outcome_tracker - Gate persist/drop decisions recorded in _flush_scratch_through_exit_gate - Consolidation promotions (goal + identity) recorded in _promote_patterns - gut.link_outcome() called after each gate decision for PCA forward-linking - KB_03 updated with OutcomeTracker integration section Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent d7c3b72 commit e7c580c

6 files changed

Lines changed: 83 additions & 9 deletions

File tree

KB/KB_03_cognitive_loop.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,14 @@ Losers decay 0.9x per cycle. User messages naturally suppress DMN.
4242
- **Command:** `/readiness` uses persistent instance (no re-creation)
4343
- When all 10 milestones achieved, bootstrap prompt stops being injected
4444

45+
## OutcomeTracker Integration (§5.3)
46+
47+
- **Lifecycle:** `OutcomeTracker` instantiated in loop, attached to `memory.outcome_tracker`
48+
- **Gate decisions:** Every persist/drop in exit gate flush records `record_gate_decision()`
49+
- **Promotions:** Consolidation `_promote_patterns` records `record_promotion()` for both goal and identity targets
50+
- **Gut linking:** `gut.link_outcome(outcome_id)` called after each gate decision, forward-linking gut deltas to outcomes
51+
- Linked outcomes available via `get_linked_outcomes()` for PCA analysis in deep consolidation
52+
4553
## Escalation Threshold
4654

4755
Adaptive: 0.3 (bootstrap) -> 0.8 (mature).

src/consolidation.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -863,6 +863,9 @@ async def _promote_patterns(self, cycle_id: str):
863863
gain = adj_gain
864864

865865
if gain > 0:
866+
old_center = float(mem["depth_weight_alpha"]) / (
867+
float(mem["depth_weight_alpha"]) + float(mem["depth_weight_beta"])
868+
)
866869
await self.memory.pool.execute(
867870
"""
868871
UPDATE memories
@@ -871,6 +874,19 @@ async def _promote_patterns(self, cycle_id: str):
871874
""",
872875
gain, mem["id"],
873876
)
877+
new_center = (float(mem["depth_weight_alpha"]) + gain) / (
878+
float(mem["depth_weight_alpha"]) + gain + float(mem["depth_weight_beta"])
879+
)
880+
# Record promotion outcome
881+
tracker = getattr(self.memory, 'outcome_tracker', None)
882+
if tracker:
883+
tracker.record_promotion(
884+
memory_id=mem["id"],
885+
from_center=old_center,
886+
to_center=new_center,
887+
gain=gain,
888+
details={"target": "goal", "cycle_id": cycle_id},
889+
)
874890
promoted_goal += 1
875891

876892
# Find memories eligible for identity-range promotion
@@ -911,6 +927,9 @@ async def _promote_patterns(self, cycle_id: str):
911927
gain = adj_gain
912928

913929
if gain > 0:
930+
old_center = float(mem["depth_weight_alpha"]) / (
931+
float(mem["depth_weight_alpha"]) + float(mem["depth_weight_beta"])
932+
)
914933
await self.memory.pool.execute(
915934
"""
916935
UPDATE memories
@@ -919,6 +938,19 @@ async def _promote_patterns(self, cycle_id: str):
919938
""",
920939
gain, mem["id"],
921940
)
941+
new_center = (float(mem["depth_weight_alpha"]) + gain) / (
942+
float(mem["depth_weight_alpha"]) + gain + float(mem["depth_weight_beta"])
943+
)
944+
# Record promotion outcome
945+
tracker = getattr(self.memory, 'outcome_tracker', None)
946+
if tracker:
947+
tracker.record_promotion(
948+
memory_id=mem["id"],
949+
from_center=old_center,
950+
to_center=new_center,
951+
gain=gain,
952+
details={"target": "identity", "cycle_id": cycle_id},
953+
)
922954
promoted_identity += 1
923955

924956
if promoted_goal or promoted_identity:

src/loop.py

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
from .bootstrap import BootstrapReadiness
3333
from .context_assembly import assemble_context, render_system_prompt, adaptive_fifo_prune
3434
from .metacognition import composite_confidence
35-
from .safety import SafetyMonitor
35+
from .safety import SafetyMonitor, OutcomeTracker
3636
from .tokens import count_tokens, count_messages_tokens
3737

3838
logger = logging.getLogger("agent.loop")
@@ -161,7 +161,10 @@ async def _run_entry_gate(gate, content, source, memory, source_tag="external_us
161161
return should_buffer, meta
162162

163163

164-
async def _flush_scratch_through_exit_gate(exit_gate, memory, layers, conversation):
164+
async def _flush_scratch_through_exit_gate(
165+
exit_gate, memory, layers, conversation,
166+
outcome_tracker=None, gut=None,
167+
):
165168
"""Periodic flush: pull scratch buffer, score each with exit gate."""
166169
entries = await memory.flush_scratch(older_than_minutes=0)
167170
if not entries:
@@ -182,6 +185,20 @@ async def _flush_scratch_through_exit_gate(exit_gate, memory, layers, conversati
182185
conversation_context=conversation,
183186
)
184187

188+
action = "persist" if should_persist else "drop"
189+
memory_id = entry.get("id", "scratch")
190+
191+
# Record gate decision in outcome tracker
192+
if outcome_tracker is not None:
193+
outcome_id = outcome_tracker.record_gate_decision(
194+
memory_id=str(memory_id),
195+
action=action,
196+
details={"gate_score": score},
197+
)
198+
# Link gut delta to this outcome
199+
if gut is not None:
200+
gut.link_outcome(outcome_id)
201+
185202
if should_persist:
186203
source_info = entry.get("source", "conversation")
187204
tags = entry.get("tags", [])
@@ -256,6 +273,11 @@ async def cognitive_loop(config, layers, memory, shutdown_event, dmn_queue=None)
256273
memory.safety = safety
257274
logger.info("Safety monitor initialized (Phase A active, B/C shadow)")
258275

276+
# Init outcome tracker (§5.3) — forward-linkable lifecycle events
277+
outcome_tracker = OutcomeTracker()
278+
memory.outcome_tracker = outcome_tracker
279+
logger.info("Outcome tracker initialized")
280+
259281
# Init gut feeling (§5.1) — two-centroid delta model
260282
gut = GutFeeling()
261283
# Seed subconscious centroid from L0/L1 layer embeddings
@@ -327,7 +349,8 @@ async def cognitive_loop(config, layers, memory, shutdown_event, dmn_queue=None)
327349
if user_input.lower() in ("exit", "quit", "/quit"):
328350
logger.info("Final scratch flush before shutdown...")
329351
await _flush_scratch_through_exit_gate(
330-
exit_gate, memory, layers, conversation
352+
exit_gate, memory, layers, conversation,
353+
outcome_tracker=outcome_tracker, gut=gut,
331354
)
332355
logger.info("User requested shutdown.")
333356
shutdown_event.set()
@@ -614,7 +637,8 @@ async def _call_retry():
614637
if exchange_count >= EXIT_GATE_FLUSH_INTERVAL:
615638
logger.info("Periodic exit gate flush triggered...")
616639
await _flush_scratch_through_exit_gate(
617-
exit_gate, memory, layers, conversation
640+
exit_gate, memory, layers, conversation,
641+
outcome_tracker=outcome_tracker, gut=gut,
618642
)
619643
exchange_count = 0
620644

@@ -799,7 +823,9 @@ async def _handle_command(
799823
if command == "/flush":
800824
print("Forcing scratch flush through exit gate...")
801825
await _flush_scratch_through_exit_gate(
802-
exit_gate, memory, layers, conversation
826+
exit_gate, memory, layers, conversation,
827+
outcome_tracker=getattr(memory, 'outcome_tracker', None),
828+
gut=gut,
803829
)
804830
print(f"Done. Exit gate stats: {exit_gate.stats}\n")
805831
return True

state/devlog.ndjson

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,5 @@
44
{"ts":"2026-02-12T10:30:00Z","type":"kb_update","msg":"KB_03_cognitive_loop.md updated with gut feeling integration section."}
55
{"ts":"2026-02-12T11:00:00Z","type":"milestone","msg":"WIRE-002 done. BootstrapReadiness wired into loop: persistent instance, check_all at startup + after flush, bootstrap prompt injected into system prompt, /readiness uses persistent instance."}
66
{"ts":"2026-02-12T11:00:00Z","type":"kb_update","msg":"KB_03_cognitive_loop.md updated with bootstrap readiness integration section."}
7+
{"ts":"2026-02-12T11:30:00Z","type":"milestone","msg":"WIRE-003 done. OutcomeTracker wired: gate decisions recorded in exit flush, promotions recorded in consolidation, gut deltas forward-linked to outcomes."}
8+
{"ts":"2026-02-12T11:30:00Z","type":"kb_update","msg":"KB_03_cognitive_loop.md updated with OutcomeTracker integration section."}

state/handoff.md

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,11 @@
9292
- `check_all()` at session start + after each exit gate flush
9393
- Bootstrap prompt injected into system prompt when milestones incomplete
9494
- `/readiness` uses persistent instance
95+
10. WIRE-003 DONE — OutcomeTracker wired into safety + consolidation:
96+
- `OutcomeTracker` instantiated in loop, attached to `memory.outcome_tracker`
97+
- Gate persist/drop decisions recorded in `_flush_scratch_through_exit_gate`
98+
- Consolidation promotions (goal + identity) recorded in `_promote_patterns`
99+
- `gut.link_outcome()` called after each gate decision
95100

96101
---
97102

@@ -108,7 +113,8 @@ Cognitive architecture for emergent AI identity. Three-layer memory unified into
108113
| FW-001 | done |
109114
| WIRE-001 | done |
110115
| WIRE-002 | done |
111-
| WIRE-003 | next - Wire OutcomeTracker into safety + consolidation |
116+
| WIRE-003 | done |
117+
| TEST-001 | next - End-to-end runtime test on norisor |
112118

113119
## What exists
114120

@@ -220,8 +226,8 @@ python3 -m src.main
220226
## Git Status
221227

222228
- **Branch:** main
223-
- **Last commit:** b95f5da Adopt AI-DEV framework + add unattended execution directive
224-
- **Modified:** KB/KB_03_cognitive_loop.md, src/loop.py, src/relevance.py, state files
229+
- **Last commit:** d7c3b72 Wire BootstrapReadiness into cognitive loop (WIRE-002)
230+
- **Modified:** src/loop.py, src/consolidation.py, KB/KB_03_cognitive_loop.md, state files
225231

226232
---
227233

state/roadmap.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@
133133
"intent": "Connect forward-linkable outcome tracking to gate decisions and consolidation",
134134
"depends_on": ["PLAN-004"],
135135
"priority": "P1",
136-
"status": "todo",
136+
"status": "done",
137137
"owner": "ai",
138138
"deliverable": "OutcomeTracker instantiated in loop, gate decisions recorded, promotions/demotions recorded, linked outcomes available for consolidation PCA",
139139
"acceptance_criteria": [

0 commit comments

Comments
 (0)