Commit Graph

2 Commits

Author SHA1 Message Date
ruv ca77f83074 feat(intelligence): unified learning-stats aggregator (ADR-075, #2245 follow-up)
Resolves the "four contradictory stat sources" item ADR-074 deferred to a
future round. Turns out the four sources aren't duplicates — they
authoritatively measure four different layers (globalStats =
trajectory-pipeline counters, sonaCoordinator = in-process SONA, memory-bridge
= AgentDB entries, neural-patterns = neural store rows). So the fix is to
aggregate the *view*, not the store.

- getUnifiedLearningStats() — returns all 4 sub-views with each sub-view
  naming its source path, plus a consistency block that *flags* cross-store
  drift (e.g. globalStats reports N patterns but neural_patterns is empty)
  instead of silently disagreeing.
- hooks_intelligence_unified-stats — new MCP tool exposing it.
- getMemoryBridgeStats() + getNeuralStoreStats() — exported helpers so any
  caller wanting a coherent learning-state snapshot uses the same primitives.

Verification:
- 7 cross-store consistency tests (__tests__/unified-stats-2245.test.ts)
- Benchmark §F added — observed: globalStats=10/11 tracks SONA, bridge=10 rows,
  neural-patterns=10, sona.available=true, 1 consistency note (the pretrain-
  vs-neural-store gap the reporter caught in #2245)
- 123/123 across unified-stats + self-learning + mcp-tools-deep

bump 3.10.14 → 3.10.15.

Co-Authored-By: RuFlo <ruv@ruv.net>
2026-05-30 12:07:26 -04:00
ruv aca2280f1c feat(intelligence): self-learning wiring + honest multi-path output (ADR-074, #2245)
The self-learning subsystem reported success but persisted nothing queryable.
Three surface-level bugs, all in the ruflo CLI's wiring of the existing
ruvector primitives (no upstream changes needed):

1. hooks_task-completed {trainPatterns:true} was a stub — hardcoded
   patternsLearned:0, ignored the trainPatterns flag entirely, noted in the
   response itself that work was "delegated to the intelligence pipeline
   (#1916 follow-up)." Now synthesizes a one-step trajectory from
   {taskId, success, quality, content} and calls recordTrajectory() on the
   real SONA + EWC++ path. Returns honest deltas and a learningPath field
   ('trajectory-pipeline' | 'recorded-only') so callers know what happened.

2. signalsProcessed was a dead counter — initialized in 3 places, read once,
   incremented zero times. Added recordSignalProcessed() to intelligence.ts
   (throttled persist) and wired it into bridgeStoreEntry. Also fixed
   loadPersistedStats() to restore patternsLearned + signalsProcessed across
   restarts (was only restoring trajectoriesRecorded — a separate "resets
   learning history on every restart" bug surfaced by the audit).

3. hooks_pretrain stored a 1-row summary bundle in the `pretrain` namespace
   but never wrote per-pattern rows to the neural store, so neural_patterns
   list returned [] right after pretrain "succeeded" with N patterns
   extracted. Now also calls storeNeuralPatterns() per pattern; surfaces
   patternsBundled + patternsIndexed + sources.stores in the response so
   callers can see exactly which stores were written.

Plus per the goal-condition "soften where possible to indicate multiple
paths":
- Every learning-adjacent handler returns explicit fields naming the path
  taken and the store(s) written.
- task-completed description lists the three paths (one-step train,
  multi-step trajectory, store-only).
- "[OK] Outcome recorded" theater replaced with notes that say what didn't
  happen as well as what did.

Plus OWASP ASI06 (Memory/Context Poisoning) hardening — basic input
sanitization on task-completed content before it feeds SONA: strip ASCII
control chars, cap to 4 KB. Surfaced by #2241 (Dream Cycle 2026-05-30).

Tests: __tests__/self-learning-2245.test.ts — 9 tests across EASY (primitives)
/ MEDIUM (MCP surfaces) / COMPLEX (multi-step + persistence) categories.

Proof harness: scripts/benchmark-self-learning.mjs — 5 sections (A–E),
writes a run JSON. Latest run: signalsProcessed +10, trained=10/10 via
trajectory pipeline at ~18 ms/call, pretrain stored=10/listed=10,
multi-step persisted=5/sonaUpdate=5. Overall: PASSED. See
docs/learning/self-learning-2245-proof.md for copy-paste reproduction.

Closes #2245.

Co-Authored-By: RuFlo <ruv@ruv.net>
2026-05-30 11:36:57 -04:00