lex-synapse 0.4.10 → 0.4.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bd6f5da400b9147f271ec3072e98e8ef1efbe3591d98ad3bd8a3908630a34d09
4
- data.tar.gz: 722bc9ac96db5bacae6d8e0723f138420f3794b83e015d44db8df683c759a2a0
3
+ metadata.gz: 868277c8084e7cd4e50c660e65cf93d3bd3554c183f8c7852bddf7ae28ff91dd
4
+ data.tar.gz: c588730afaa91b1842f35eb3e20584445ebb6f62d2e1042831de6942f9b712e7
5
5
  SHA512:
6
- metadata.gz: 743363f5855fc61423255bccd553c419f06705124debd8d5f378609d5e8da1c1a35e4f2a5f02027a9fc8c22648fc860fb18269fa1875ebf26d3bce177def2155
7
- data.tar.gz: 351f68075a8ef8a13754324e6d829103b383b96bb6837c03add4b211dd181fe6cb67063c45dac630b5a352d661bfcd843d450689bab4c88a2acc10f59ab7e0b1
6
+ metadata.gz: 63aa10dd7948c59e7f3f603748a2bfa5bca217aad2dd99d05e898cdf9b102358c21f66b73d4eb258f81fed54b1c90dca23ce6569f942fa9db632fd269c564a8b
7
+ data.tar.gz: dc9a028d79dca386c03672a46237d1190c8001ee35c9704630ed9b8f310ba38322983176d02d178ab979b2695699cbd0178addb4f890d5fe03b498bce4c1008b
data/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.4.12] - 2026-05-07
4
+ ### Fixed
5
+ - Added challenge proposal application through the mutate runner so auto-accepted proposals can advance to `applied` and later resolve challenger outcomes.
6
+ - Averaged resolved LLM challenger confidence, auto-accepted all-abstain challenges, and ensured proactive proposals store a non-empty candidate output.
7
+ - Look up target function schemas through extension discovery when building transform proposals.
8
+
9
+ ## [0.4.11] - 2026-04-22
10
+ ### Fixed
11
+ - `handle_pain` now actually calls `revert` when consecutive failures reach threshold (was only setting a flag)
12
+ - `analyze_routing` stub now logs warning instead of silently returning nil
13
+ - Silent rescue blocks in `retrieve#parse_pattern` and `propose#call_llm` now log errors
14
+
3
15
  ## [0.4.10] - 2026-04-15
4
16
  ### Changed
5
17
  - Set `mcp_tools?` and `mcp_tools_deferred?` to `false` — internal infrastructure extension, not an LLM-callable tool
data/CLAUDE.md CHANGED
@@ -1,8 +1,8 @@
1
1
  # lex-synapse: Cognitive Routing Layer for LegionIO
2
2
 
3
3
  **Repository Level 3 Documentation**
4
- - **Parent**: `/Users/miverso2/rubymine/legion/extensions-core/CLAUDE.md`
5
- - **Grandparent**: `/Users/miverso2/rubymine/legion/CLAUDE.md`
4
+ - **Parent**: `../CLAUDE.md`
5
+ - **Grandparent**: `../../CLAUDE.md`
6
6
 
7
7
  ## Purpose
8
8
 
@@ -10,7 +10,7 @@ Cognitive routing layer that wraps task chain relationships with observation, le
10
10
 
11
11
  **GitHub**: https://github.com/LegionIO/lex-synapse
12
12
  **License**: MIT
13
- **Version**: 0.4.0
13
+ **Version**: 0.4.11
14
14
 
15
15
  ## Architecture
16
16
 
@@ -22,19 +22,19 @@ Legion::Extensions::Synapse
22
22
  │ ├── Crystallize # Every 300s — emergent synapse detection
23
23
  │ ├── Homeostasis # Every 30s — spike/drought monitoring
24
24
  │ ├── Decay # Every 3600s — idle confidence decay
25
- │ ├── Propose # Every 300s — proactive proposal analysis for AUTONOMOUS synapses
26
- │ └── Challenge # Every 60s — adversarial challenge pipeline for pending proposals
25
+ │ ├── Propose # Every 300s — proactive proposal analysis for AUTONOMOUS synapses
26
+ │ └── Challenge # Every 60s — adversarial challenge pipeline for pending proposals
27
27
  ├── Runners/
28
- │ ├── Evaluate # attention -> transform -> route -> record
29
- │ ├── Pain # failure recording, confidence hit, auto-revert
28
+ │ ├── Evaluate # attention -> transform -> route -> record -> propose (if AUTONOMOUS)
29
+ │ ├── Pain # failure recording, confidence hit, auto-revert (calls revert!), dampen
30
30
  │ ├── Crystallize # unrouted traffic analysis, emergent creation
31
- │ ├── Mutate # versioned self-modification with snapshots
32
- │ ├── Revert # rollback to previous mutation version
31
+ │ ├── Mutate # versioned self-modification with before/after snapshots
32
+ │ ├── Revert # rollback to previous mutation version (restores before_state)
33
33
  │ ├── Report # aggregate stats for GAIA consumption
34
- │ ├── Dream # replay historical signals in simulation mode; replay/simulate
34
+ │ ├── Dream # replay historical signals in simulation mode
35
35
  │ ├── GaiaReport # GAIA tick hook: report confidence and health per synapse
36
- │ ├── Promote # Apollo integration: promote high-confidence synapse patterns to shared knowledge
37
- │ ├── Retrieve # Apollo integration: retrieve relevant synapse patterns from shared knowledge
36
+ │ ├── Promote # Apollo integration: promote high-confidence synapse patterns
37
+ │ ├── Retrieve # Apollo integration: retrieve relevant synapse patterns
38
38
  │ ├── Propose # reactive (signal-driven) + proactive (periodic) proposal generation
39
39
  │ └── Challenge # conflict detection, LLM challenge, weighted aggregation, outcome resolution
40
40
  ├── Helpers/
@@ -43,7 +43,7 @@ Legion::Extensions::Synapse
43
43
  │ ├── RelationshipWrapper # Layer 1 -> Layer 2 wrapping
44
44
  │ └── Challenge # settings, constants, impact threshold helpers
45
45
  ├── Data/
46
- │ ├── Migrations/ # 001 synapses, 002 mutations, 003 signals, 004 proposals, 005 challenges
46
+ │ ├── Migrations/ # 001 synapses, 002 mutations, 003 signals, 004 proposals, 005 challenges, 006 slow_query_indexes, 007 blast_radius
47
47
  │ └── Models/ # Synapse, SynapseMutation, SynapseSignal, SynapseProposal, SynapseChallenge
48
48
  ├── Transport/
49
49
  │ ├── Exchanges/Synapse
@@ -52,6 +52,24 @@ Legion::Extensions::Synapse
52
52
  └── Client # Standalone client including all runners
53
53
  ```
54
54
 
55
+ ## Runner Methods (Public API)
56
+
57
+ | Runner | Method | Signature |
58
+ |---|---|---|
59
+ | Evaluate | `evaluate` | `evaluate(synapse_id:, payload: {}, conditioner_client: nil, transformer_client: nil)` |
60
+ | Pain | `handle_pain` | `handle_pain(synapse_id:, task_id: nil)` — records failure, adjusts confidence, calls `revert` on 3+ consecutive failures |
61
+ | Crystallize | `crystallize` | `crystallize(signal_pairs:, threshold: 20)` |
62
+ | Mutate | `mutate` | `mutate(synapse_id:, mutation_type:, changes:, trigger:)` |
63
+ | Revert | `revert` | `revert(synapse_id:, to_version: nil, trigger: 'pain')` — restores `before_state` from mutation record; records revert as new mutation |
64
+ | Report | `report` | `report(synapse_id:)` |
65
+ | Dream | `dream` | `dream(synapse_id:, limit:)` |
66
+ | GaiaReport | `gaia_report` | Called during GAIA tick cycle |
67
+ | Promote | `promote` | `promote(synapse_id:)` |
68
+ | Retrieve | `retrieve` | `retrieve(...)` |
69
+ | Propose | `propose`, `proposals`, `review_proposal` | `propose(synapse_id:, ...)` / `proposals(synapse_id:, status:)` / `review_proposal(proposal_id:, status:)` |
70
+ | Challenge | `challenge_proposal`, `challenges`, `challenger_stats` | `challenge_proposal(proposal_id:)` / `challenges(proposal_id:)` / `challenger_stats` |
71
+ | Blast Radius | `analyze_routing` | `analyze_routing(synapse_id:)` — logs blast radius analysis result |
72
+
55
73
  ## Key Thresholds
56
74
 
57
75
  | Parameter | Value |
@@ -76,44 +94,34 @@ Legion::Extensions::Synapse
76
94
  | 0.0-0.3 | OBSERVE | Log, pass through unchanged |
77
95
  | 0.3-0.6 | FILTER | Suppress signals |
78
96
  | 0.6-0.8 | TRANSFORM | Filter + transform within schemas |
79
- | 0.8-1.0 | AUTONOMOUS | Self-modify rules, infer transforms |
97
+ | 0.8-1.0 | AUTONOMOUS | Self-modify rules via proposals, infer transforms |
98
+
99
+ ## Pain Auto-Revert
100
+
101
+ `Runners::Pain#handle_pain` calls `revert(synapse_id:, trigger: 'pain')` directly when `consecutive_failures >= 3`. The revert finds the latest mutation record for the synapse's current version, restores `before_state` (attention, transform, routing_strategy, confidence, status), decrements version, marks the mutation outcome as `'reverted'`, and creates a new mutation record with `outcome: 'reverted'`.
80
102
 
81
103
  ## Data Model
82
104
 
83
- - **synapses**: Core routing definition with confidence, status, version, baseline_throughput
84
- - **synapse_mutations**: Versioned change history with before/after JSON snapshots
85
- - **synapse_signals**: Per-signal outcome records (attention pass, transform success, latency, downstream outcome)
86
- - **synapse_proposals**: Proposed changes with status lifecycle, challenge_state, challenge_score, impact_score
105
+ - **synapses**: Core routing definition with confidence, status, version, baseline_throughput, blast_radius
106
+ - **synapse_mutations**: Versioned change history with before/after JSON snapshots, trigger, outcome
107
+ - **synapse_signals**: Per-signal outcome records (attention pass, transform success, latency_ms, downstream outcome)
108
+ - **synapse_proposals**: Proposed changes with status lifecycle (pending → approved/rejected/applied/expired/auto_accepted/auto_rejected), challenge_state, challenge_score, impact_score
87
109
  - **synapse_challenges**: Per-challenge verdicts (conflict/LLM), confidence tracking, outcome resolution
88
110
 
89
111
  ## Autonomous Observation Mode (v0.3.0)
90
112
 
91
- - **Proposal engine**: AUTONOMOUS tier (confidence 0.8+) generates proposals instead of executing autonomous actions
92
- - **Reactive proposals**: on signal evaluation — no-template inference, transform failure fix, attention pain correlation
93
- - **Proactive proposals**: periodic analysis — success rate degradation, payload drift detection
94
- - **LLM-backed**: proposals call lex-transformer LLM engine for real output generation
95
- - **Settings**: `lex-synapse.proposals.*` — enabled, reactive, proactive, max_per_run, llm_engine_options, thresholds
96
- - **Data**: `synapse_proposals` table with status lifecycle (pending -> approved/rejected/applied/expired)
97
- - **Client methods**: `proposals(synapse_id:, status:)`, `review_proposal(proposal_id:, status:)`
113
+ AUTONOMOUS-tier synapses (confidence >= 0.8) generate proposals instead of executing autonomous actions. Proposals are reactive (triggered on signal evaluation in `Runners::Evaluate`) or proactive (generated periodically by `Actors::Propose`). Settings: `lex-synapse.proposals.*` (enabled, reactive, proactive, max_per_run, llm_engine_options, thresholds).
98
114
 
99
115
  ## Adversarial Challenge Phase (v0.4.0)
100
116
 
101
- - **Challenge pipeline**: pending proposals go through conflict detection (mechanical) -> impact scoring -> LLM challenge (gated) -> weighted aggregation -> auto-accept/reject/await-review
102
- - **Conflict detection**: queries sibling pending proposals on same synapse; conflicting types produce 'challenge' verdict
103
- - **LLM challenge**: gated by `impact_score >= 0.3`; calls lex-transformer LLM engine; parses SUPPORT/CHALLENGE/ABSTAIN
104
- - **Aggregation**: `support_weight / (support_weight + challenge_weight)`, abstains excluded; >= 0.85 auto-accepts, <= 0.15 auto-rejects
105
- - **Challenger confidence**: starting 0.5, correct +0.05, incorrect -0.08, decay *0.998/hr; tracks via outcome resolution after observation window (50 signals post-application)
106
- - **Settings**: `lex-synapse.challenge.*` — enabled, impact_threshold, auto_accept_threshold, auto_reject_threshold, llm_engine_options, outcome_observation_window, max_per_cycle
107
- - **Data**: `synapse_challenges` table; `synapse_proposals` gains challenge_state, challenge_score, impact_score columns
108
- - **Statuses**: `auto_accepted`, `auto_rejected` added to proposal lifecycle
109
- - **Client methods**: `challenge_proposal(proposal_id:)`, `challenges(proposal_id:)`, `challenger_stats`
117
+ Pending proposals pass through: conflict detection impact scoring LLM challenge (gated by `impact_score >= 0.3`) weighted aggregation auto-accept/reject. Aggregation: `support_weight / (support_weight + challenge_weight)`, >= 0.85 auto-accepts, <= 0.15 auto-rejects. Settings: `lex-synapse.challenge.*`.
110
118
 
111
119
  ## GAIA / Apollo Integration (v0.2.2)
112
120
 
113
- - **GaiaReport runner**: Called during the GAIA tick cycle to report per-synapse confidence and health metrics.
114
- - **Dream runner**: Replays historical signals in simulation mode. Used by the dream cycle to test routing hypothesis changes without affecting live state.
115
- - **Promote runner**: Publishes high-confidence synapse patterns to the Apollo shared knowledge store when confidence exceeds threshold.
116
- - **Retrieve runner**: Pulls relevant synapse patterns from Apollo to seed new synapses or adjust confidence for cold-start scenarios.
121
+ - **GaiaReport**: Called during GAIA tick to report per-synapse confidence and health metrics
122
+ - **Dream**: Replays historical signals in simulation without affecting live state
123
+ - **Promote**: Publishes high-confidence patterns to Apollo shared knowledge store
124
+ - **Retrieve**: Pulls relevant patterns from Apollo to seed new synapses or adjust confidence
117
125
 
118
126
  ## Dependencies
119
127
 
@@ -121,7 +129,13 @@ Legion::Extensions::Synapse
121
129
  |-----|---------|
122
130
  | `lex-conditioner` >= 0.3.0 | Attention evaluation (condition rules) |
123
131
  | `lex-transformer` >= 0.3.0 | Payload transformation (template engines) |
124
- | `legion-data` | Required database persistence via Sequel |
132
+ | `legion-cache` >= 1.3.11 | Cache access |
133
+ | `legion-crypt` >= 1.4.9 | Encryption/Vault |
134
+ | `legion-data` >= 1.4.17 | Required — database persistence via Sequel |
135
+ | `legion-json` >= 1.2.1 | JSON serialization |
136
+ | `legion-logging` >= 1.3.2 | Logging |
137
+ | `legion-settings` >= 1.3.14 | Settings |
138
+ | `legion-transport` >= 1.3.9 | AMQP |
125
139
 
126
140
  ## Testing
127
141
 
@@ -131,7 +145,7 @@ bundle exec rspec # 412 specs, 0 failures
131
145
  bundle exec rubocop # 0 offenses
132
146
  ```
133
147
 
134
- 412 specs, 94%+ coverage. Uses in-memory SQLite for model/runner tests.
148
+ Uses in-memory SQLite for model/runner tests.
135
149
 
136
150
  ---
137
151
 
data/README.md CHANGED
@@ -70,7 +70,7 @@ Each synapse has a confidence score (0.0-1.0) that governs what it's allowed to
70
70
  | 0.0-0.3 | OBSERVE | Log what it would do, pass through unchanged |
71
71
  | 0.3-0.6 | FILTER | Can suppress signals, cannot modify |
72
72
  | 0.6-0.8 | TRANSFORM | Can filter + transform within defined schemas |
73
- | 0.8-1.0 | AUTONOMOUS | Can self-modify rules, infer transforms, adjust routing |
73
+ | 0.8-1.0 | AUTONOMOUS | Generates proposals for self-modification |
74
74
 
75
75
  **Starting scores**: explicit=0.7, emergent=0.3, seeded=0.5
76
76
 
@@ -82,7 +82,7 @@ Each synapse has a confidence score (0.0-1.0) that governs what it's allowed to
82
82
 
83
83
  Downstream task failures propagate backward through the chain:
84
84
  - Each failure reduces confidence by 0.05
85
- - 3+ consecutive failures trigger auto-revert to last known-good state
85
+ - 3+ consecutive failures trigger auto-revert to last known-good state (calls `revert` directly)
86
86
  - Extreme failure rates trigger dampening (homeostasis)
87
87
 
88
88
  ### Homeostasis
@@ -96,27 +96,27 @@ Downstream task failures propagate backward through the chain:
96
96
  ### Evaluate
97
97
  `evaluate(synapse_id:, payload:, conditioner_client:, transformer_client:)`
98
98
 
99
- Main signal flow: load synapse, check autonomy, run attention (conditioner), run transform (transformer), record signal, adjust confidence.
99
+ Main signal flow: load synapse check autonomy run attention (conditioner) run transform (transformer) record signal adjust confidence → generate proposals if AUTONOMOUS.
100
100
 
101
101
  ### Pain
102
102
  `handle_pain(synapse_id:, task_id:)`
103
103
 
104
- Downstream failure handler. Records failed signal, adjusts confidence, checks for auto-revert threshold, may dampen synapse.
104
+ Downstream failure handler. Records failed signal, adjusts confidence, calls `revert` on 3+ consecutive failures, may dampen synapse.
105
+
106
+ ### Revert
107
+ `revert(synapse_id:, to_version:, trigger:)`
108
+
109
+ Rolls back to a previous mutation version, restoring `before_state`. Records the revert as a new mutation entry.
105
110
 
106
111
  ### Crystallize
107
112
  `crystallize(signal_pairs:, threshold: 20)`
108
113
 
109
- Bottom-up emergence. Given pairs of `{source_function_id, target_function_id, count}`, creates new synapses for pairs exceeding the threshold.
114
+ Bottom-up emergence. Creates new synapses for source/target pairs exceeding the threshold.
110
115
 
111
116
  ### Mutate
112
117
  `mutate(synapse_id:, mutation_type:, changes:, trigger:)`
113
118
 
114
- Versioned self-modification. Records before/after state snapshots. Types: `attention_adjusted`, `transform_adjusted`, `route_changed`, `confidence_changed`. Triggers: `hebbian`, `pain`, `dream`, `gaia`, `manual`.
115
-
116
- ### Revert
117
- `revert(synapse_id:, to_version:, trigger:)`
118
-
119
- Rolls back to a previous mutation version, restoring the before_state.
119
+ Versioned self-modification. Records before/after state snapshots.
120
120
 
121
121
  ### Report
122
122
  `report(synapse_id:)`
@@ -126,17 +126,10 @@ Aggregates stats: confidence, status, 24h signal count, success rate, last mutat
126
126
  ### Dream
127
127
  `dream(synapse_id:, limit:)`
128
128
 
129
- Replays historical signals in simulation mode without affecting live state. Used by the dream cycle to test routing hypothesis changes.
130
-
131
- ### Propose
132
- `propose(synapse_id:, ...)` / `proposals(synapse_id:, status:)` / `review_proposal(proposal_id:, status:)`
133
-
134
- Generates proposed changes (reactive on signal evaluation, proactive on periodic analysis) for AUTONOMOUS-tier synapses. Proposals enter a status lifecycle: pending -> approved/rejected/applied/expired/auto_accepted/auto_rejected.
135
-
136
- ### Challenge
137
- `challenge_proposal(proposal_id:)` / `challenges(proposal_id:)` / `challenger_stats`
129
+ Replays historical signals in simulation mode without affecting live state.
138
130
 
139
- Runs the adversarial challenge pipeline on pending proposals: conflict detection -> impact scoring -> LLM challenge (gated by impact score) -> weighted aggregation -> auto-accept/reject/await-review outcome.
131
+ ### Propose / Challenge
132
+ AUTONOMOUS-tier synapses generate proposals (reactive on evaluation, proactive periodically). Proposals are subjected to a multi-stage challenge pipeline: conflict detection → impact scoring → optional LLM challenge → weighted aggregation → auto-accept/reject.
140
133
 
141
134
  ## Relationship Wrapper
142
135
 
@@ -148,24 +141,16 @@ relationship = { id: 42, trigger_function_id: 1, function_id: 2,
148
141
  synapse = Legion::Extensions::Synapse::Helpers::RelationshipWrapper.wrap(relationship)
149
142
  ```
150
143
 
144
+ ## Data Model
145
+
146
+ Five tables: `synapses` (core routing + confidence + status + blast_radius), `synapse_mutations` (versioned history), `synapse_signals` (per-signal outcomes), `synapse_proposals` (proposal lifecycle), `synapse_challenges` (per-challenge verdicts).
147
+
151
148
  ## Transport
152
149
 
153
150
  - **Exchange**: `synapse` (inherits from `Legion::Transport::Exchanges::Task`)
154
151
  - **Queues**: `synapse.evaluate`, `synapse.pain`
155
152
  - **Routing keys**: `synapse.evaluate`, `task.failed`
156
153
 
157
- ## Autonomous Observation Mode
158
-
159
- AUTONOMOUS-tier synapses (confidence >= 0.8) generate proposals instead of directly executing changes. Proposals are reactive (triggered on signal evaluation) or proactive (generated periodically). The `lex-synapse.proposals.*` settings control enabled state, LLM engine options, and thresholds.
160
-
161
- ## Adversarial Challenge Phase
162
-
163
- Pending proposals are subjected to a multi-stage challenge pipeline: conflict detection among sibling proposals, impact scoring, optional LLM challenge (for high-impact proposals), weighted aggregation across verdicts, and auto-accept/reject based on configurable thresholds. The `lex-synapse.challenge.*` settings control gating.
164
-
165
- ## Data Model
166
-
167
- Five tables: `synapses` (core routing definition + confidence + status), `synapse_mutations` (versioned change history), `synapse_signals` (per-signal outcome records), `synapse_proposals` (proposal lifecycle), `synapse_challenges` (per-challenge verdicts).
168
-
169
154
  ## Dependencies
170
155
 
171
156
  - `lex-conditioner` >= 0.3.0
@@ -7,6 +7,7 @@ require_relative '../data/models/synapse_proposal'
7
7
  require_relative '../data/models/synapse_challenge'
8
8
  require_relative '../data/models/synapse_signal'
9
9
  require_relative 'blast_radius'
10
+ require_relative 'mutate'
10
11
 
11
12
  module Legion
12
13
  module Extensions
@@ -87,10 +88,37 @@ module Legion
87
88
  { success: true, proposal_id: proposal_id, success_rate: success_rate, resolved: challenges.size }
88
89
  end
89
90
 
91
+ def apply_proposal(proposal_id:)
92
+ Data::Model.define_synapse_proposal_model
93
+ Data::Model.define_synapse_model
94
+
95
+ proposal = Data::Model::SynapseProposal[proposal_id]
96
+ return { success: false, error: 'proposal not found' } unless proposal
97
+ return { success: false, error: 'proposal not approved' } unless %w[approved auto_accepted].include?(proposal.status)
98
+ return { success: false, error: 'proposal output missing' } if proposal.output.nil? || proposal.output.to_s.strip.empty?
99
+
100
+ synapse = Data::Model::Synapse[proposal.synapse_id]
101
+ return { success: false, error: 'synapse not found' } unless synapse
102
+
103
+ mutation = mutation_for_proposal(proposal)
104
+ return { success: false, error: "unsupported proposal_type: #{proposal.proposal_type}" } unless mutation
105
+
106
+ result = Object.new.extend(Mutate).mutate(
107
+ synapse_id: proposal.synapse_id,
108
+ mutation_type: mutation[:mutation_type],
109
+ changes: mutation[:changes],
110
+ trigger: 'gaia'
111
+ )
112
+ return result unless result[:success]
113
+
114
+ proposal.update(status: 'applied', reviewed_at: Time.now)
115
+ result.merge(proposal_id: proposal.id, status: 'applied', decision: 'applied')
116
+ end
117
+
90
118
  def run_challenge_cycle(transformer_client: nil)
91
119
  Data::Model.define_synapse_proposal_model
92
120
  Data::Model.define_synapse_challenge_model
93
- return { challenged: 0, resolved: 0 } unless Helpers::Challenge.enabled?
121
+ return { challenged: 0, applied: 0, resolved: 0 } unless Helpers::Challenge.enabled?
94
122
 
95
123
  settings = Helpers::Challenge.settings
96
124
  max = settings[:max_per_cycle] || 5
@@ -101,6 +129,12 @@ module Legion
101
129
  challenged += 1
102
130
  end
103
131
 
132
+ applied = 0
133
+ Data::Model::SynapseProposal.where(status: 'auto_accepted').order(Sequel.asc(:id)).limit(max).each do |proposal|
134
+ result = apply_proposal(proposal_id: proposal.id)
135
+ applied += 1 if result[:success]
136
+ end
137
+
104
138
  resolved = 0
105
139
  window = settings[:outcome_observation_window] || 50
106
140
  Data::Model.define_synapse_signal_model
@@ -118,11 +152,22 @@ module Legion
118
152
  resolved += 1
119
153
  end
120
154
 
121
- { challenged: challenged, resolved: resolved }
155
+ { challenged: challenged, applied: applied, resolved: resolved }
122
156
  end
123
157
 
124
158
  private
125
159
 
160
+ def mutation_for_proposal(proposal)
161
+ case proposal.proposal_type
162
+ when 'llm_transform', 'transform_mutation'
163
+ { mutation_type: 'transform_adjusted', changes: { transform: proposal.output } }
164
+ when 'attention_mutation'
165
+ { mutation_type: 'attention_adjusted', changes: { attention: proposal.output } }
166
+ when 'route_change'
167
+ { mutation_type: 'route_changed', changes: { routing_strategy: proposal.output } }
168
+ end
169
+ end
170
+
126
171
  def conflict_check(proposal)
127
172
  conflicts = Data::Model::SynapseProposal.where(
128
173
  synapse_id: proposal.synapse_id,
@@ -176,8 +221,8 @@ module Legion
176
221
  .exclude(verdict: 'abstain').all
177
222
 
178
223
  if challenges.empty?
179
- proposal.update(challenge_state: 'challenged', challenge_score: 0.5)
180
- return { success: true, challenge_score: 0.5, decision: 'challenged' }
224
+ proposal.update(status: 'auto_accepted', challenge_state: 'challenged', challenge_score: 0.0)
225
+ return { success: true, challenge_score: 0.0, decision: 'auto_accepted' }
181
226
  end
182
227
 
183
228
  support_weight = challenges.select { |c| c.verdict == 'support' }.sum(&:challenger_confidence)
@@ -253,7 +298,7 @@ module Legion
253
298
  .order(Sequel.desc(:id)).limit(20).all
254
299
  return Helpers::Challenge.settings[:challenger_starting_confidence] if recent.empty?
255
300
 
256
- recent.first.challenger_confidence
301
+ recent.sum(&:challenger_confidence).to_f / recent.size
257
302
  end
258
303
 
259
304
  include Legion::Extensions::Helpers::Lex if defined?(Legion::Extensions::Helpers::Lex)
@@ -38,7 +38,8 @@ module Legion
38
38
  # Auto-revert on 3+ consecutive failures
39
39
  if consecutive >= CONSECUTIVE_FAILURE_THRESHOLD
40
40
  result[:action] = :auto_revert
41
- result[:reverted] = true
41
+ revert_result = revert(synapse_id: synapse_id, trigger: 'pain')
42
+ result[:reverted] = revert_result[:success] == true
42
43
  end
43
44
 
44
45
  # Check if confidence dropped below autonomy threshold
@@ -11,6 +11,8 @@ module Legion
11
11
  module Synapse
12
12
  module Runners
13
13
  module Propose
14
+ include Legion::Logging::Helper if defined?(Legion::Logging::Helper)
15
+
14
16
  PAIN_CORRELATION_THRESHOLD = 3
15
17
 
16
18
  def propose_reactive(synapse:, payload:, signal_id:, attention_result:, transform_result:,
@@ -133,7 +135,7 @@ module Legion
133
135
  synapse: synapse, signal_id: nil, proposal_type: 'transform_mutation',
134
136
  trigger: 'proactive',
135
137
  inputs: Legion::JSON.dump({ success_rate: rate.round(3), sample_size: signals.size, threshold: threshold }),
136
- output: nil,
138
+ output: proactive_transform_output(synapse, success_rate: rate.round(3), sample_size: signals.size),
137
139
  rationale: "success rate #{(rate * 100).round(1)}% below threshold #{(threshold * 100).round(1)}%"
138
140
  )
139
141
  end
@@ -154,7 +156,7 @@ module Legion
154
156
  synapse: synapse, signal_id: nil, proposal_type: 'transform_mutation',
155
157
  trigger: 'proactive',
156
158
  inputs: Legion::JSON.dump({ drift_rate: drift_rate.round(3), sample_size: signals.size }),
157
- output: nil,
159
+ output: proactive_transform_output(synapse, drift_rate: drift_rate.round(3), sample_size: signals.size),
158
160
  rationale: "payload drift detected: #{(drift_rate * 100).round(1)}% transform failures in recent signals"
159
161
  )
160
162
  end
@@ -165,6 +167,8 @@ module Legion
165
167
  signals = Data::Model::SynapseSignal.where(synapse_id: synapse.id).order(Sequel.desc(:id)).limit(50).all
166
168
  return nil if signals.size < 10
167
169
 
170
+ # TODO: implement routing analysis (e.g. detect latency patterns that suggest a better route)
171
+ log.warn("analyze_routing: no routing analysis implemented for synapse #{synapse.id}")
168
172
  nil
169
173
  end
170
174
 
@@ -210,7 +214,7 @@ module Legion
210
214
  )
211
215
  { output: result[:success] ? Legion::JSON.dump(result[:result]) : nil }
212
216
  rescue StandardError => e
213
- log.warn("Proposal LLM call failed: #{e.message}")
217
+ log.error("Proposal LLM call failed: #{e.message}")
214
218
  { output: nil }
215
219
  end
216
220
 
@@ -222,9 +226,25 @@ module Legion
222
226
 
223
227
  def lookup_target_schema(synapse)
224
228
  return {} unless synapse.target_function_id
225
- return {} unless defined?(Legion::Extensions::Lex)
226
229
 
227
- {}
230
+ discovery_schema(synapse.target_function_id) || {}
231
+ end
232
+
233
+ def discovery_schema(function_id)
234
+ discovery = defined?(Legion::Extensions::Discovery) && Legion::Extensions::Discovery
235
+ return unless discovery.respond_to?(:function_schema)
236
+
237
+ discovery.function_schema(function_id)
238
+ rescue StandardError => e
239
+ log.debug("lookup_target_schema failed for #{function_id}: #{e.message}")
240
+ nil
241
+ end
242
+
243
+ def proactive_transform_output(synapse, **metadata)
244
+ existing = synapse.transform.to_s.strip
245
+ return existing unless existing.empty?
246
+
247
+ Legion::JSON.dump(metadata.merge(action: 'review_transform', synapse_id: synapse.id))
228
248
  end
229
249
 
230
250
  def build_transform_prompt(source_schema, target_schema)
@@ -8,6 +8,8 @@ module Legion
8
8
  module Synapse
9
9
  module Runners
10
10
  module Retrieve
11
+ include Legion::Logging::Helper if defined?(Legion::Logging::Helper)
12
+
11
13
  SEED_CONFIDENCE_THRESHOLD = 0.7
12
14
 
13
15
  def retrieve_and_seed(knowledge_entries:, **)
@@ -45,7 +47,8 @@ module Legion
45
47
  return nil unless content
46
48
 
47
49
  content.is_a?(String) ? Legion::JSON.load(content) : content
48
- rescue StandardError => _e
50
+ rescue StandardError => e
51
+ log.error("parse_pattern failed: #{e.message}")
49
52
  nil
50
53
  end
51
54
 
@@ -3,7 +3,7 @@
3
3
  module Legion
4
4
  module Extensions
5
5
  module Synapse
6
- VERSION = '0.4.10'
6
+ VERSION = '0.4.12'
7
7
  end
8
8
  end
9
9
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lex-synapse
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.10
4
+ version: 0.4.12
5
5
  platform: ruby
6
6
  authors:
7
7
  - Esity