lex-cognitive-tectonics 0.1.0
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 +7 -0
- data/.github/workflows/ci.yml +16 -0
- data/.gitignore +11 -0
- data/.rspec +2 -0
- data/.rubocop.yml +64 -0
- data/CLAUDE.md +137 -0
- data/Gemfile +13 -0
- data/README.md +62 -0
- data/lex-cognitive-tectonics.gemspec +30 -0
- data/lib/legion/extensions/cognitive_tectonics/actors/drift_tick.rb +41 -0
- data/lib/legion/extensions/cognitive_tectonics/client.rb +18 -0
- data/lib/legion/extensions/cognitive_tectonics/helpers/belief_plate.rb +85 -0
- data/lib/legion/extensions/cognitive_tectonics/helpers/constants.rb +36 -0
- data/lib/legion/extensions/cognitive_tectonics/helpers/seismic_event.rb +53 -0
- data/lib/legion/extensions/cognitive_tectonics/helpers/tectonic_engine.rb +214 -0
- data/lib/legion/extensions/cognitive_tectonics/runners/cognitive_tectonics.rb +71 -0
- data/lib/legion/extensions/cognitive_tectonics/version.rb +9 -0
- data/lib/legion/extensions/cognitive_tectonics.rb +19 -0
- metadata +79 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 6beef28cd3264b3978f5e982e00fca770a6b80b5d63a29d8155b5208ae8d399a
|
|
4
|
+
data.tar.gz: 9a9c401d00654e2473066da9be054972920e2f257cda552d18f1a1c51fef03bb
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 10e34cf80558cac6f3a5fe4e06c05bc7153b68d2501145451f592964d8902d84e1c383fcbe894fd05daea10093da39cf9fe4ce015dc1191b4d901a282a221de2
|
|
7
|
+
data.tar.gz: 4afbe3e1eb7bcc4360f8e5609de40fc58bd597347189a4d6945a299b298f58dfd93bcca364aad017e416dbe533dc10b38b3d0b362af822fa7d77cd43e82b24af
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
on:
|
|
3
|
+
push:
|
|
4
|
+
branches: [main]
|
|
5
|
+
pull_request:
|
|
6
|
+
|
|
7
|
+
jobs:
|
|
8
|
+
ci:
|
|
9
|
+
uses: LegionIO/.github/.github/workflows/ci.yml@main
|
|
10
|
+
|
|
11
|
+
release:
|
|
12
|
+
needs: ci
|
|
13
|
+
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
|
|
14
|
+
uses: LegionIO/.github/.github/workflows/release.yml@main
|
|
15
|
+
secrets:
|
|
16
|
+
rubygems-api-key: ${{ secrets.RUBYGEMS_API_KEY }}
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.rubocop.yml
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
AllCops:
|
|
2
|
+
TargetRubyVersion: 3.4
|
|
3
|
+
NewCops: enable
|
|
4
|
+
SuggestExtensions: false
|
|
5
|
+
|
|
6
|
+
Layout/LineLength:
|
|
7
|
+
Max: 160
|
|
8
|
+
|
|
9
|
+
Layout/SpaceAroundEqualsInParameterDefault:
|
|
10
|
+
EnforcedStyle: space
|
|
11
|
+
|
|
12
|
+
Layout/HashAlignment:
|
|
13
|
+
EnforcedHashRocketStyle: table
|
|
14
|
+
EnforcedColonStyle: table
|
|
15
|
+
|
|
16
|
+
Metrics/MethodLength:
|
|
17
|
+
Max: 25
|
|
18
|
+
|
|
19
|
+
Metrics/ClassLength:
|
|
20
|
+
Max: 150
|
|
21
|
+
|
|
22
|
+
Metrics/ModuleLength:
|
|
23
|
+
Max: 150
|
|
24
|
+
|
|
25
|
+
Metrics/BlockLength:
|
|
26
|
+
Max: 40
|
|
27
|
+
Exclude:
|
|
28
|
+
- 'spec/**/*'
|
|
29
|
+
|
|
30
|
+
Metrics/AbcSize:
|
|
31
|
+
Max: 25
|
|
32
|
+
|
|
33
|
+
Metrics/ParameterLists:
|
|
34
|
+
Max: 8
|
|
35
|
+
MaxOptionalParameters: 8
|
|
36
|
+
|
|
37
|
+
Metrics/CyclomaticComplexity:
|
|
38
|
+
Max: 15
|
|
39
|
+
|
|
40
|
+
Metrics/PerceivedComplexity:
|
|
41
|
+
Max: 17
|
|
42
|
+
|
|
43
|
+
Style/Documentation:
|
|
44
|
+
Enabled: false
|
|
45
|
+
|
|
46
|
+
Style/SymbolArray:
|
|
47
|
+
Enabled: true
|
|
48
|
+
|
|
49
|
+
Style/FrozenStringLiteralComment:
|
|
50
|
+
Enabled: true
|
|
51
|
+
EnforcedStyle: always
|
|
52
|
+
|
|
53
|
+
Style/OneClassPerFile:
|
|
54
|
+
Exclude:
|
|
55
|
+
- 'spec/spec_helper.rb'
|
|
56
|
+
|
|
57
|
+
Naming/FileName:
|
|
58
|
+
Enabled: false
|
|
59
|
+
|
|
60
|
+
Naming/PredicateMethod:
|
|
61
|
+
Enabled: false
|
|
62
|
+
|
|
63
|
+
Naming/PredicatePrefix:
|
|
64
|
+
Enabled: false
|
data/CLAUDE.md
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
# lex-cognitive-tectonics
|
|
2
|
+
|
|
3
|
+
**Level 3 Leaf Documentation**
|
|
4
|
+
- **Parent**: `/Users/miverso2/rubymine/legion/extensions-agentic/CLAUDE.md`
|
|
5
|
+
- **Gem**: `lex-cognitive-tectonics`
|
|
6
|
+
- **Version**: 0.1.0
|
|
7
|
+
- **Namespace**: `Legion::Extensions::CognitiveTectonics`
|
|
8
|
+
|
|
9
|
+
## Purpose
|
|
10
|
+
|
|
11
|
+
Models belief revision as plate tectonics. Cognitive beliefs are represented as plates with mass, position, and drift vectors in a 2D space. Plates drift over time, collide, and interact via three boundary types: convergent (beliefs merge), divergent (beliefs split and drift apart), or transform (friction accumulates stress that eventually triggers earthquakes). Seismic events model sudden, cascading belief shifts. A periodic `DriftTick` actor moves all plates each tick.
|
|
12
|
+
|
|
13
|
+
## Gem Info
|
|
14
|
+
|
|
15
|
+
- **Gemspec**: `lex-cognitive-tectonics.gemspec`
|
|
16
|
+
- **Require**: `lex-cognitive-tectonics`
|
|
17
|
+
- **Ruby**: >= 3.4
|
|
18
|
+
- **License**: MIT
|
|
19
|
+
- **Homepage**: https://github.com/LegionIO/lex-cognitive-tectonics
|
|
20
|
+
|
|
21
|
+
## File Structure
|
|
22
|
+
|
|
23
|
+
```
|
|
24
|
+
lib/legion/extensions/cognitive_tectonics/
|
|
25
|
+
version.rb
|
|
26
|
+
helpers/
|
|
27
|
+
constants.rb # Boundary types, magnitude labels, stress/collision thresholds
|
|
28
|
+
belief_plate.rb # BeliefPlate class — one belief with position, mass, stress
|
|
29
|
+
seismic_event.rb # SeismicEvent class — earthquake/tremor/aftershock record
|
|
30
|
+
tectonic_engine.rb # TectonicBoundaries module + TectonicEngine class
|
|
31
|
+
runners/
|
|
32
|
+
cognitive_tectonics.rb # Runner module — public API (extend self)
|
|
33
|
+
actors/
|
|
34
|
+
drift_tick.rb # Actor::DriftTick — fires drift_tick every 60s
|
|
35
|
+
client.rb
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Key Constants
|
|
39
|
+
|
|
40
|
+
| Constant | Value | Meaning |
|
|
41
|
+
|---|---|---|
|
|
42
|
+
| `MAX_PLATES` | 50 | Hard cap on belief plates (raises if exceeded) |
|
|
43
|
+
| `MAX_QUAKES` | 200 | Seismic history ring size |
|
|
44
|
+
| `COLLISION_THRESHOLD` | 0.2 | Distance below which two plates collide |
|
|
45
|
+
| `SUBDUCTION_RATIO` | 0.7 | Mass below which a plate is subductable |
|
|
46
|
+
| `AFTERSHOCK_DECAY` | 0.3 | Magnitude multiplier reduction for aftershocks |
|
|
47
|
+
| `STRESS_QUAKE_TRIGGER` | 1.0 | Stress accumulation that auto-triggers earthquake |
|
|
48
|
+
| `MIN_DRIFT_RATE` | 0.001 | Minimum allowed drift component (reference) |
|
|
49
|
+
| `MAX_DRIFT_RATE` | 0.05 | Maximum allowed drift component (reference) |
|
|
50
|
+
|
|
51
|
+
`BOUNDARY_TYPES`: `[:convergent, :divergent, :transform]`
|
|
52
|
+
|
|
53
|
+
`PLATE_STATES`: `[:active, :subducted, :dormant]`
|
|
54
|
+
|
|
55
|
+
Magnitude labels: `[0,1)` = `:micro`, `[1,2)` = `:minor`, `[2,3)` = `:light`, `[3,4)` = `:moderate`, `[4,5)` = `:strong`, `5+` = `:great`
|
|
56
|
+
|
|
57
|
+
## Key Classes
|
|
58
|
+
|
|
59
|
+
### `Helpers::BeliefPlate`
|
|
60
|
+
|
|
61
|
+
One cognitive belief with spatial position, mass, drift, and stress.
|
|
62
|
+
|
|
63
|
+
- `drift!(delta_t)` — advances position by `drift_vector * delta_t`; only active plates drift
|
|
64
|
+
- `accumulate_stress!(amount)` — adds to `@stress_accumulation`
|
|
65
|
+
- `release_stress!` — resets stress to 0.0; returns the released amount
|
|
66
|
+
- `subducted?` — mass < `SUBDUCTION_RATIO`
|
|
67
|
+
- `subduct!` / `dormant!` — transitions state
|
|
68
|
+
- `active?` — `state == :active`
|
|
69
|
+
- `distance_to(other_plate)` — Euclidean distance between positions
|
|
70
|
+
- Position is initialized with random `x,y` in `[-10.0, 10.0]` if not provided
|
|
71
|
+
|
|
72
|
+
### `Helpers::SeismicEvent`
|
|
73
|
+
|
|
74
|
+
A seismic event record for the history log.
|
|
75
|
+
|
|
76
|
+
- `EVENT_TYPES`: `[:earthquake, :tremor, :aftershock]`
|
|
77
|
+
- `label` — magnitude label from `Constants#label_for`
|
|
78
|
+
- `aftershock?` — type == `:aftershock`
|
|
79
|
+
- Fields: `id`, `type`, `magnitude`, `epicenter_plate_id`, `affected_plate_ids`, `parent_event_id`, `timestamp`
|
|
80
|
+
|
|
81
|
+
### `Helpers::TectonicBoundaries` (module)
|
|
82
|
+
|
|
83
|
+
Private collision resolution methods mixed into `TectonicEngine`.
|
|
84
|
+
|
|
85
|
+
- `resolve_convergent` — averages mass and drift vectors; outcome `:merged`
|
|
86
|
+
- `resolve_divergent` — halves mass; reverses x-drift for A, y-drift for B; outcome `:split`
|
|
87
|
+
- `resolve_transform` — adds `mass_a * mass_b * 0.5` stress to both; calls `check_stress_quake`; outcome `:friction`
|
|
88
|
+
- `check_stress_quake` — auto-triggers earthquake if plate stress >= `STRESS_QUAKE_TRIGGER`
|
|
89
|
+
|
|
90
|
+
### `Helpers::TectonicEngine`
|
|
91
|
+
|
|
92
|
+
Registry and event processing.
|
|
93
|
+
|
|
94
|
+
- `create_plate(domain:, content:, mass:, drift_vector:, position:)` — raises if at `MAX_PLATES`
|
|
95
|
+
- `drift_tick!(delta_t)` — drifts all active plates; detects collisions afterward
|
|
96
|
+
- `detect_collisions` — all active plate pairs with distance < `COLLISION_THRESHOLD`
|
|
97
|
+
- `resolve_collision(plate_a_id:, plate_b_id:, boundary_type:)` — dispatches to `TectonicBoundaries`; updates fault registry
|
|
98
|
+
- `subduct(weaker_plate_id:, stronger_plate_id:)` — absorbs 50% of weaker plate's mass into stronger; marks weaker as subducted
|
|
99
|
+
- `trigger_earthquake(plate_id:, magnitude:)` — releases stress; propagates 30% magnitude to nearby plates (< 5.0 distance)
|
|
100
|
+
- `aftershock_cascade(event_id:)` — creates aftershock at `magnitude * (1 - AFTERSHOCK_DECAY)`
|
|
101
|
+
- `tectonic_report` — aggregate with plate counts, high-stress count, recent quakes
|
|
102
|
+
|
|
103
|
+
## Runners
|
|
104
|
+
|
|
105
|
+
Module: `Legion::Extensions::CognitiveTectonics::Runners::CognitiveTectonics` (uses `extend self`)
|
|
106
|
+
|
|
107
|
+
| Runner | Key Args | Returns |
|
|
108
|
+
|---|---|---|
|
|
109
|
+
| `create_plate` | `domain:`, `content:`, `mass:`, `drift_vector:`, `position:` | `{ success:, plate_id:, plate: }` |
|
|
110
|
+
| `drift_tick` | `delta_t:` | `{ success:, plates_moved:, collisions_detected:, collisions: }` |
|
|
111
|
+
| `resolve_collision` | `plate_a_id:`, `plate_b_id:`, `boundary_type:` | boundary-specific result hash |
|
|
112
|
+
| `trigger_earthquake` | `plate_id:`, `magnitude:` | `{ success:, event_id:, event: }` |
|
|
113
|
+
| `tectonic_status` | — | `{ success:, total_plates:, active_plates:, high_stress_count:, recent_quakes:, ... }` |
|
|
114
|
+
|
|
115
|
+
## Actors
|
|
116
|
+
|
|
117
|
+
`Actor::DriftTick` — extends `Legion::Extensions::Actors::Every`
|
|
118
|
+
|
|
119
|
+
- Fires `drift_tick` every **60 seconds**
|
|
120
|
+
- `run_now?: false`, `use_runner?: false`, `check_subtask?: false`, `generate_task?: false`
|
|
121
|
+
- Advances all plate positions and surfaces new collisions each minute
|
|
122
|
+
|
|
123
|
+
## Integration Points
|
|
124
|
+
|
|
125
|
+
- `drift_tick` is called automatically every 60s by `Actor::DriftTick`
|
|
126
|
+
- Can be triggered manually via runner for faster simulation
|
|
127
|
+
- Collision detection returns plate ID pairs — caller decides the boundary type for `resolve_collision`
|
|
128
|
+
- Transform boundary is the only type that accumulates stress; high-stress states can be read via `tectonic_report`
|
|
129
|
+
- All state is in-memory per `TectonicEngine` instance; reset is not built in (replace `@tectonic_engine`)
|
|
130
|
+
|
|
131
|
+
## Development Notes
|
|
132
|
+
|
|
133
|
+
- `MIN_DRIFT_RATE` and `MAX_DRIFT_RATE` are defined but not enforced; drift components in `drift_vector` are caller-specified
|
|
134
|
+
- `nearby_plates` uses a fixed radius of 5.0 (hardcoded in `TectonicBoundaries`)
|
|
135
|
+
- The runner raises `ArgumentError` directly for missing required args, then rescues it into `{ success: false, error: }`
|
|
136
|
+
- Fault registry (`@active_faults`) is a plain array of hashes, not indexed — O(n) for lookup
|
|
137
|
+
- Seismic history is a ring buffer capped at `MAX_QUAKES`: `@seismic_history.shift if size > MAX_QUAKES`
|
data/Gemfile
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
source 'https://rubygems.org'
|
|
4
|
+
|
|
5
|
+
gemspec
|
|
6
|
+
|
|
7
|
+
group :test do
|
|
8
|
+
gem 'rspec', '~> 3.13'
|
|
9
|
+
gem 'rubocop', '~> 1.75', require: false
|
|
10
|
+
gem 'rubocop-rspec', require: false
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
gem 'legion-gaia', path: '../../legion-gaia'
|
data/README.md
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# lex-cognitive-tectonics
|
|
2
|
+
|
|
3
|
+
A LegionIO cognitive architecture extension that models belief revision as plate tectonics. Beliefs drift through conceptual space, collide, and interact via convergent, divergent, or transform boundaries. Stress accumulates and releases as earthquakes — sudden, cascading belief shifts.
|
|
4
|
+
|
|
5
|
+
## What It Does
|
|
6
|
+
|
|
7
|
+
Manages **belief plates** — cognitive beliefs with position, mass, and drift velocity in a 2D space. A background actor moves all plates every 60 seconds. When plates collide, the caller resolves the interaction by choosing a boundary type:
|
|
8
|
+
|
|
9
|
+
- **Convergent**: beliefs merge; masses and drifts average together
|
|
10
|
+
- **Divergent**: beliefs split and drift apart; mass halves
|
|
11
|
+
- **Transform**: friction builds stress; at threshold stress triggers an earthquake
|
|
12
|
+
|
|
13
|
+
Earthquakes release stress and propagate to nearby plates.
|
|
14
|
+
|
|
15
|
+
## Usage
|
|
16
|
+
|
|
17
|
+
```ruby
|
|
18
|
+
require 'lex-cognitive-tectonics'
|
|
19
|
+
|
|
20
|
+
client = Legion::Extensions::CognitiveTectonics::Client.new
|
|
21
|
+
|
|
22
|
+
# Create belief plates
|
|
23
|
+
r1 = client.create_plate(domain: :ethics, content: 'harm prevention is primary', mass: 0.8,
|
|
24
|
+
drift_vector: { x: 0.01, y: 0.0 })
|
|
25
|
+
# => { success: true, plate_id: "uuid...", plate: { mass: 0.8, state: :active, position: {...}, ... } }
|
|
26
|
+
|
|
27
|
+
r2 = client.create_plate(domain: :ethics, content: 'autonomy is primary', mass: 0.7,
|
|
28
|
+
drift_vector: { x: -0.01, y: 0.0 })
|
|
29
|
+
|
|
30
|
+
# Advance one tick (also fires automatically every 60s via Actor::DriftTick)
|
|
31
|
+
client.drift_tick(delta_t: 1.0)
|
|
32
|
+
# => { success: true, plates_moved: 2, collisions_detected: 0, collisions: [] }
|
|
33
|
+
|
|
34
|
+
# If plates collide, resolve the interaction
|
|
35
|
+
# (plates with distance < 0.2 are flagged as collisions)
|
|
36
|
+
client.resolve_collision(
|
|
37
|
+
plate_a_id: r1[:plate_id],
|
|
38
|
+
plate_b_id: r2[:plate_id],
|
|
39
|
+
boundary_type: :transform
|
|
40
|
+
)
|
|
41
|
+
# => { success: true, boundary_type: :transform, outcome: :friction, stress_added: 0.28 }
|
|
42
|
+
|
|
43
|
+
# Manually trigger an earthquake at a plate
|
|
44
|
+
client.trigger_earthquake(plate_id: r1[:plate_id], magnitude: 2.5)
|
|
45
|
+
# => { success: true, event_id: "uuid...", event: { type: :earthquake, magnitude: 2.5, label: :light, ... } }
|
|
46
|
+
|
|
47
|
+
# System report
|
|
48
|
+
client.tectonic_status
|
|
49
|
+
# => { success: true, total_plates: 2, active_plates: 2, high_stress_count: 0, seismic_events: 1, ... }
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Development
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
bundle install
|
|
56
|
+
bundle exec rspec
|
|
57
|
+
bundle exec rubocop
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## License
|
|
61
|
+
|
|
62
|
+
MIT
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'lib/legion/extensions/cognitive_tectonics/version'
|
|
4
|
+
|
|
5
|
+
Gem::Specification.new do |spec|
|
|
6
|
+
spec.name = 'lex-cognitive-tectonics'
|
|
7
|
+
spec.version = Legion::Extensions::CognitiveTectonics::VERSION
|
|
8
|
+
spec.authors = ['Esity']
|
|
9
|
+
spec.email = ['matthewdiverson@gmail.com']
|
|
10
|
+
|
|
11
|
+
spec.summary = 'LEX Cognitive Tectonics'
|
|
12
|
+
spec.description = 'Tectonic belief-plate model for LegionIO — conviction as mass, drift vectors, ' \
|
|
13
|
+
'convergent/divergent/transform boundaries, seismic belief shifts, and aftershock cascades'
|
|
14
|
+
spec.homepage = 'https://github.com/LegionIO/lex-cognitive-tectonics'
|
|
15
|
+
spec.license = 'MIT'
|
|
16
|
+
spec.required_ruby_version = '>= 3.4'
|
|
17
|
+
|
|
18
|
+
spec.metadata['homepage_uri'] = spec.homepage
|
|
19
|
+
spec.metadata['source_code_uri'] = 'https://github.com/LegionIO/lex-cognitive-tectonics'
|
|
20
|
+
spec.metadata['documentation_uri'] = 'https://github.com/LegionIO/lex-cognitive-tectonics'
|
|
21
|
+
spec.metadata['changelog_uri'] = 'https://github.com/LegionIO/lex-cognitive-tectonics'
|
|
22
|
+
spec.metadata['bug_tracker_uri'] = 'https://github.com/LegionIO/lex-cognitive-tectonics/issues'
|
|
23
|
+
spec.metadata['rubygems_mfa_required'] = 'true'
|
|
24
|
+
|
|
25
|
+
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
|
26
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
|
27
|
+
end
|
|
28
|
+
spec.require_paths = ['lib']
|
|
29
|
+
spec.add_development_dependency 'legion-gaia'
|
|
30
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'legion/extensions/actors/every'
|
|
4
|
+
|
|
5
|
+
module Legion
|
|
6
|
+
module Extensions
|
|
7
|
+
module CognitiveTectonics
|
|
8
|
+
module Actor
|
|
9
|
+
class DriftTick < Legion::Extensions::Actors::Every
|
|
10
|
+
def runner_class
|
|
11
|
+
Legion::Extensions::CognitiveTectonics::Runners::CognitiveTectonics
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def runner_function
|
|
15
|
+
'drift_tick'
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def time
|
|
19
|
+
60
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def run_now?
|
|
23
|
+
false
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def use_runner?
|
|
27
|
+
false
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def check_subtask?
|
|
31
|
+
false
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def generate_task?
|
|
35
|
+
false
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
module Extensions
|
|
5
|
+
module CognitiveTectonics
|
|
6
|
+
class Client
|
|
7
|
+
include Runners::CognitiveTectonics
|
|
8
|
+
|
|
9
|
+
attr_reader :engine
|
|
10
|
+
|
|
11
|
+
def initialize(engine: nil, **)
|
|
12
|
+
@engine = engine || Helpers::TectonicEngine.new
|
|
13
|
+
@tectonic_engine = @engine
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'securerandom'
|
|
4
|
+
|
|
5
|
+
module Legion
|
|
6
|
+
module Extensions
|
|
7
|
+
module CognitiveTectonics
|
|
8
|
+
module Helpers
|
|
9
|
+
class BeliefPlate
|
|
10
|
+
include Constants
|
|
11
|
+
|
|
12
|
+
attr_reader :id, :domain, :content, :created_at, :state
|
|
13
|
+
attr_accessor :mass, :drift_vector, :position, :velocity, :stress_accumulation
|
|
14
|
+
|
|
15
|
+
def initialize(domain:, content:, mass: 0.5, drift_vector: nil, position: nil, **)
|
|
16
|
+
@id = SecureRandom.uuid
|
|
17
|
+
@domain = domain
|
|
18
|
+
@content = content
|
|
19
|
+
@mass = mass.clamp(0.0, 1.0)
|
|
20
|
+
@drift_vector = drift_vector || { x: 0.0, y: 0.0 }
|
|
21
|
+
@position = position || { x: rand(-10.0..10.0).round(10), y: rand(-10.0..10.0).round(10) }
|
|
22
|
+
@velocity = { x: 0.0, y: 0.0 }
|
|
23
|
+
@stress_accumulation = 0.0
|
|
24
|
+
@state = :active
|
|
25
|
+
@created_at = Time.now.utc
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def drift!(delta_t = 1.0)
|
|
29
|
+
return if @state != :active
|
|
30
|
+
|
|
31
|
+
@position[:x] = (@position[:x] + (@drift_vector.fetch(:x, 0.0) * delta_t)).round(10)
|
|
32
|
+
@position[:y] = (@position[:y] + (@drift_vector.fetch(:y, 0.0) * delta_t)).round(10)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def accumulate_stress!(amount)
|
|
36
|
+
@stress_accumulation = (@stress_accumulation + amount.abs).round(10)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def release_stress!
|
|
40
|
+
released = @stress_accumulation
|
|
41
|
+
@stress_accumulation = 0.0
|
|
42
|
+
released
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def subducted?
|
|
46
|
+
@mass < Constants::SUBDUCTION_RATIO
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def subduct!
|
|
50
|
+
@state = :subducted
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def dormant!
|
|
54
|
+
@state = :dormant
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def active?
|
|
58
|
+
@state == :active
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def distance_to(other_plate)
|
|
62
|
+
dx = @position[:x] - other_plate.position[:x]
|
|
63
|
+
dy = @position[:y] - other_plate.position[:y]
|
|
64
|
+
Math.sqrt((dx**2) + (dy**2)).round(10)
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def to_h
|
|
68
|
+
{
|
|
69
|
+
id: @id,
|
|
70
|
+
domain: @domain,
|
|
71
|
+
content: @content,
|
|
72
|
+
mass: @mass,
|
|
73
|
+
drift_vector: @drift_vector,
|
|
74
|
+
position: @position,
|
|
75
|
+
velocity: @velocity,
|
|
76
|
+
stress_accumulation: @stress_accumulation,
|
|
77
|
+
state: @state,
|
|
78
|
+
created_at: @created_at
|
|
79
|
+
}
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
module Extensions
|
|
5
|
+
module CognitiveTectonics
|
|
6
|
+
module Helpers
|
|
7
|
+
module Constants
|
|
8
|
+
MAX_PLATES = 50
|
|
9
|
+
MAX_QUAKES = 200
|
|
10
|
+
BOUNDARY_TYPES = %i[convergent divergent transform].freeze
|
|
11
|
+
MIN_DRIFT_RATE = 0.001
|
|
12
|
+
MAX_DRIFT_RATE = 0.05
|
|
13
|
+
COLLISION_THRESHOLD = 0.2
|
|
14
|
+
SUBDUCTION_RATIO = 0.7
|
|
15
|
+
AFTERSHOCK_DECAY = 0.3
|
|
16
|
+
STRESS_QUAKE_TRIGGER = 1.0
|
|
17
|
+
|
|
18
|
+
PLATE_STATES = %i[active subducted dormant].freeze
|
|
19
|
+
|
|
20
|
+
MAGNITUDE_LABELS = {
|
|
21
|
+
(0.0...1.0) => :micro,
|
|
22
|
+
(1.0...2.0) => :minor,
|
|
23
|
+
(2.0...3.0) => :light,
|
|
24
|
+
(3.0...4.0) => :moderate,
|
|
25
|
+
(4.0...5.0) => :strong,
|
|
26
|
+
(5.0...Float::INFINITY) => :great
|
|
27
|
+
}.freeze
|
|
28
|
+
|
|
29
|
+
def label_for(magnitude)
|
|
30
|
+
MAGNITUDE_LABELS.find { |range, _| range.cover?(magnitude) }&.last || :unknown
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'securerandom'
|
|
4
|
+
|
|
5
|
+
module Legion
|
|
6
|
+
module Extensions
|
|
7
|
+
module CognitiveTectonics
|
|
8
|
+
module Helpers
|
|
9
|
+
class SeismicEvent
|
|
10
|
+
include Constants
|
|
11
|
+
|
|
12
|
+
EVENT_TYPES = %i[earthquake tremor aftershock].freeze
|
|
13
|
+
|
|
14
|
+
attr_reader :id, :type, :magnitude, :epicenter_plate_id,
|
|
15
|
+
:affected_plate_ids, :timestamp, :parent_event_id
|
|
16
|
+
|
|
17
|
+
def initialize(type:, magnitude:, epicenter_plate_id:, affected_plate_ids: [], parent_event_id: nil, **)
|
|
18
|
+
raise ArgumentError, "unknown event type: #{type.inspect}" unless EVENT_TYPES.include?(type)
|
|
19
|
+
|
|
20
|
+
@id = SecureRandom.uuid
|
|
21
|
+
@type = type
|
|
22
|
+
@magnitude = magnitude.clamp(0.0, Float::INFINITY)
|
|
23
|
+
@epicenter_plate_id = epicenter_plate_id
|
|
24
|
+
@affected_plate_ids = Array(affected_plate_ids)
|
|
25
|
+
@parent_event_id = parent_event_id
|
|
26
|
+
@timestamp = Time.now.utc
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def aftershock?
|
|
30
|
+
@type == :aftershock
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def label
|
|
34
|
+
label_for(@magnitude)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def to_h
|
|
38
|
+
{
|
|
39
|
+
id: @id,
|
|
40
|
+
type: @type,
|
|
41
|
+
magnitude: @magnitude,
|
|
42
|
+
label: label,
|
|
43
|
+
epicenter_plate_id: @epicenter_plate_id,
|
|
44
|
+
affected_plate_ids: @affected_plate_ids,
|
|
45
|
+
parent_event_id: @parent_event_id,
|
|
46
|
+
timestamp: @timestamp
|
|
47
|
+
}
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
module Extensions
|
|
5
|
+
module CognitiveTectonics
|
|
6
|
+
module Helpers
|
|
7
|
+
module TectonicBoundaries
|
|
8
|
+
private
|
|
9
|
+
|
|
10
|
+
def resolve_convergent(plate_a, plate_b)
|
|
11
|
+
combined = ((plate_a.mass + plate_b.mass) / 2.0).clamp(0.0, 1.0)
|
|
12
|
+
plate_a.mass = combined
|
|
13
|
+
plate_b.mass = combined
|
|
14
|
+
avg_drift = {
|
|
15
|
+
x: ((plate_a.drift_vector[:x] + plate_b.drift_vector[:x]) / 2.0).round(10),
|
|
16
|
+
y: ((plate_a.drift_vector[:y] + plate_b.drift_vector[:y]) / 2.0).round(10)
|
|
17
|
+
}
|
|
18
|
+
plate_a.drift_vector = avg_drift
|
|
19
|
+
plate_b.drift_vector = avg_drift
|
|
20
|
+
{ success: true, boundary_type: :convergent, outcome: :merged, new_mass: combined }
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def resolve_divergent(plate_a, plate_b)
|
|
24
|
+
split_mass = (plate_a.mass * 0.5).round(10)
|
|
25
|
+
plate_a.mass = split_mass
|
|
26
|
+
plate_b.mass = split_mass
|
|
27
|
+
plate_a.drift_vector = { x: -plate_a.drift_vector.fetch(:x, 0.0), y: plate_a.drift_vector.fetch(:y, 0.0) }
|
|
28
|
+
plate_b.drift_vector = { x: plate_b.drift_vector.fetch(:x, 0.0), y: -plate_b.drift_vector.fetch(:y, 0.0) }
|
|
29
|
+
{ success: true, boundary_type: :divergent, outcome: :split, new_mass: split_mass }
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def resolve_transform(plate_a, plate_b)
|
|
33
|
+
stress = (plate_a.mass * plate_b.mass * 0.5).round(10)
|
|
34
|
+
plate_a.accumulate_stress!(stress)
|
|
35
|
+
plate_b.accumulate_stress!(stress)
|
|
36
|
+
check_stress_quake(plate_a)
|
|
37
|
+
check_stress_quake(plate_b)
|
|
38
|
+
{ success: true, boundary_type: :transform, outcome: :friction, stress_added: stress }
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def check_stress_quake(plate)
|
|
42
|
+
return unless plate.stress_accumulation >= Constants::STRESS_QUAKE_TRIGGER
|
|
43
|
+
|
|
44
|
+
trigger_earthquake(plate_id: plate.id, magnitude: plate.stress_accumulation)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def nearby_plates(plate, exclude_id:)
|
|
48
|
+
@plates.values.select do |p|
|
|
49
|
+
p.active? && p.id != exclude_id && plate.distance_to(p) < 5.0
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def record_seismic_event(event)
|
|
54
|
+
@seismic_history << event
|
|
55
|
+
@seismic_history.shift if @seismic_history.size > Constants::MAX_QUAKES
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def update_active_faults(plate_a_id, plate_b_id, boundary_type)
|
|
59
|
+
existing = @active_faults.find { |f| fault_matches?(f, plate_a_id, plate_b_id) }
|
|
60
|
+
if existing
|
|
61
|
+
existing[:boundary_type] = boundary_type
|
|
62
|
+
existing[:last_activity] = Time.now.utc
|
|
63
|
+
else
|
|
64
|
+
@active_faults << { plate_a_id: plate_a_id, plate_b_id: plate_b_id,
|
|
65
|
+
boundary_type: boundary_type, last_activity: Time.now.utc }
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def fault_matches?(fault, id_a, id_b)
|
|
70
|
+
(fault[:plate_a_id] == id_a && fault[:plate_b_id] == id_b) ||
|
|
71
|
+
(fault[:plate_a_id] == id_b && fault[:plate_b_id] == id_a)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def remove_faults_for(plate_id)
|
|
75
|
+
@active_faults.reject! { |f| f[:plate_a_id] == plate_id || f[:plate_b_id] == plate_id }
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def avg_mass(plates)
|
|
79
|
+
return 0.0 if plates.empty?
|
|
80
|
+
|
|
81
|
+
(plates.sum(&:mass) / plates.size.to_f).round(10)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def recent_earthquakes(count)
|
|
85
|
+
@seismic_history.last(count).map(&:to_h)
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
class TectonicEngine
|
|
90
|
+
include Constants
|
|
91
|
+
include TectonicBoundaries
|
|
92
|
+
|
|
93
|
+
attr_reader :plates, :seismic_history, :active_faults
|
|
94
|
+
|
|
95
|
+
def initialize
|
|
96
|
+
@plates = {}
|
|
97
|
+
@seismic_history = []
|
|
98
|
+
@active_faults = []
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def create_plate(domain:, content:, mass: 0.5, drift_vector: nil, position: nil, **)
|
|
102
|
+
raise ArgumentError, 'plate limit reached' if @plates.size >= Constants::MAX_PLATES
|
|
103
|
+
|
|
104
|
+
plate = BeliefPlate.new(domain: domain, content: content,
|
|
105
|
+
mass: mass, drift_vector: drift_vector, position: position)
|
|
106
|
+
@plates[plate.id] = plate
|
|
107
|
+
{ success: true, plate_id: plate.id, plate: plate.to_h }
|
|
108
|
+
rescue ArgumentError => e
|
|
109
|
+
{ success: false, error: e.message }
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def drift_tick!(delta_t = 1.0, **)
|
|
113
|
+
moved = 0
|
|
114
|
+
@plates.each_value do |plate|
|
|
115
|
+
next unless plate.active?
|
|
116
|
+
|
|
117
|
+
plate.drift!(delta_t)
|
|
118
|
+
moved += 1
|
|
119
|
+
end
|
|
120
|
+
collisions = detect_collisions
|
|
121
|
+
{ success: true, plates_moved: moved, collisions_detected: collisions.size, collisions: collisions }
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def detect_collisions
|
|
125
|
+
active = @plates.values.select(&:active?)
|
|
126
|
+
pairs = active.combination(2).select { |a, b| a.distance_to(b) < Constants::COLLISION_THRESHOLD }
|
|
127
|
+
pairs.map { |a, b| { plate_a_id: a.id, plate_b_id: b.id, distance: a.distance_to(b) } }
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def resolve_collision(plate_a_id:, plate_b_id:, boundary_type:, **)
|
|
131
|
+
raise ArgumentError, "unknown boundary type: #{boundary_type}" unless Constants::BOUNDARY_TYPES.include?(boundary_type)
|
|
132
|
+
|
|
133
|
+
plate_a = @plates[plate_a_id]
|
|
134
|
+
plate_b = @plates[plate_b_id]
|
|
135
|
+
raise ArgumentError, "plate not found: #{plate_a_id}" unless plate_a
|
|
136
|
+
raise ArgumentError, "plate not found: #{plate_b_id}" unless plate_b
|
|
137
|
+
|
|
138
|
+
result = send(:"resolve_#{boundary_type}", plate_a, plate_b)
|
|
139
|
+
update_active_faults(plate_a_id, plate_b_id, boundary_type)
|
|
140
|
+
result
|
|
141
|
+
rescue ArgumentError => e
|
|
142
|
+
{ success: false, error: e.message }
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def subduct(weaker_plate_id:, stronger_plate_id:, **)
|
|
146
|
+
weaker = @plates[weaker_plate_id]
|
|
147
|
+
stronger = @plates[stronger_plate_id]
|
|
148
|
+
raise ArgumentError, "plate not found: #{weaker_plate_id}" unless weaker
|
|
149
|
+
raise ArgumentError, "plate not found: #{stronger_plate_id}" unless stronger
|
|
150
|
+
|
|
151
|
+
mass_absorbed = weaker.mass * 0.5
|
|
152
|
+
stronger.mass = (stronger.mass + mass_absorbed).clamp(0.0, 1.0)
|
|
153
|
+
weaker.subduct!
|
|
154
|
+
remove_faults_for(weaker_plate_id)
|
|
155
|
+
{ success: true, subducted_plate_id: weaker_plate_id, mass_absorbed: mass_absorbed.round(10) }
|
|
156
|
+
rescue ArgumentError => e
|
|
157
|
+
{ success: false, error: e.message }
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
def trigger_earthquake(plate_id:, magnitude:, **)
|
|
161
|
+
plate = @plates[plate_id]
|
|
162
|
+
raise ArgumentError, "plate not found: #{plate_id}" unless plate
|
|
163
|
+
|
|
164
|
+
nearby = nearby_plates(plate, exclude_id: plate_id)
|
|
165
|
+
event = SeismicEvent.new(type: :earthquake, magnitude: magnitude,
|
|
166
|
+
epicenter_plate_id: plate_id, affected_plate_ids: nearby.map(&:id))
|
|
167
|
+
record_seismic_event(event)
|
|
168
|
+
plate.release_stress!
|
|
169
|
+
nearby.each { |p| p.accumulate_stress!(magnitude * 0.3) }
|
|
170
|
+
{ success: true, event_id: event.id, event: event.to_h }
|
|
171
|
+
rescue ArgumentError => e
|
|
172
|
+
{ success: false, error: e.message }
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
def aftershock_cascade(event_id:, **)
|
|
176
|
+
parent = @seismic_history.find { |e| e.id == event_id }
|
|
177
|
+
raise ArgumentError, "event not found: #{event_id}" unless parent
|
|
178
|
+
|
|
179
|
+
decayed_magnitude = (parent.magnitude * (1.0 - Constants::AFTERSHOCK_DECAY)).round(10)
|
|
180
|
+
return { success: true, aftershocks: [], reason: :magnitude_too_low } if decayed_magnitude < 0.1
|
|
181
|
+
|
|
182
|
+
aftershock = SeismicEvent.new(type: :aftershock, magnitude: decayed_magnitude,
|
|
183
|
+
epicenter_plate_id: parent.epicenter_plate_id,
|
|
184
|
+
affected_plate_ids: parent.affected_plate_ids,
|
|
185
|
+
parent_event_id: event_id)
|
|
186
|
+
record_seismic_event(aftershock)
|
|
187
|
+
{ success: true, aftershocks: [aftershock.to_h] }
|
|
188
|
+
rescue ArgumentError => e
|
|
189
|
+
{ success: false, error: e.message }
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
def all_plates
|
|
193
|
+
@plates.values.map(&:to_h)
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
def tectonic_report
|
|
197
|
+
active_plates, subducted_plates = @plates.values.partition(&:active?)
|
|
198
|
+
high_stress = active_plates.select { |p| p.stress_accumulation > 0.5 }
|
|
199
|
+
{
|
|
200
|
+
total_plates: @plates.size,
|
|
201
|
+
active_plates: active_plates.size,
|
|
202
|
+
subducted_plates: subducted_plates.size,
|
|
203
|
+
high_stress_count: high_stress.size,
|
|
204
|
+
seismic_events: @seismic_history.size,
|
|
205
|
+
active_faults: @active_faults.size,
|
|
206
|
+
avg_mass: avg_mass(active_plates),
|
|
207
|
+
recent_quakes: recent_earthquakes(5)
|
|
208
|
+
}
|
|
209
|
+
end
|
|
210
|
+
end
|
|
211
|
+
end
|
|
212
|
+
end
|
|
213
|
+
end
|
|
214
|
+
end
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Legion
|
|
4
|
+
module Extensions
|
|
5
|
+
module CognitiveTectonics
|
|
6
|
+
module Runners
|
|
7
|
+
module CognitiveTectonics
|
|
8
|
+
extend self
|
|
9
|
+
|
|
10
|
+
include Legion::Extensions::Helpers::Lex if defined?(Legion::Extensions::Helpers::Lex)
|
|
11
|
+
|
|
12
|
+
def create_plate(domain: nil, content: nil, mass: 0.5, drift_vector: nil, position: nil, engine: nil, **)
|
|
13
|
+
raise ArgumentError, 'domain is required' if domain.nil?
|
|
14
|
+
raise ArgumentError, 'content is required' if content.nil?
|
|
15
|
+
|
|
16
|
+
tectonic_engine(engine).create_plate(
|
|
17
|
+
domain: domain,
|
|
18
|
+
content: content,
|
|
19
|
+
mass: mass,
|
|
20
|
+
drift_vector: drift_vector,
|
|
21
|
+
position: position
|
|
22
|
+
)
|
|
23
|
+
rescue ArgumentError => e
|
|
24
|
+
{ success: false, error: e.message }
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def drift_tick(delta_t: 1.0, engine: nil, **)
|
|
28
|
+
tectonic_engine(engine).drift_tick!(delta_t)
|
|
29
|
+
rescue ArgumentError => e
|
|
30
|
+
{ success: false, error: e.message }
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def resolve_collision(plate_a_id: nil, plate_b_id: nil, boundary_type: :convergent, engine: nil, **)
|
|
34
|
+
raise ArgumentError, 'plate_a_id is required' if plate_a_id.nil?
|
|
35
|
+
raise ArgumentError, 'plate_b_id is required' if plate_b_id.nil?
|
|
36
|
+
|
|
37
|
+
tectonic_engine(engine).resolve_collision(
|
|
38
|
+
plate_a_id: plate_a_id,
|
|
39
|
+
plate_b_id: plate_b_id,
|
|
40
|
+
boundary_type: boundary_type
|
|
41
|
+
)
|
|
42
|
+
rescue ArgumentError => e
|
|
43
|
+
{ success: false, error: e.message }
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def trigger_earthquake(plate_id: nil, magnitude: 1.0, engine: nil, **)
|
|
47
|
+
raise ArgumentError, 'plate_id is required' if plate_id.nil?
|
|
48
|
+
|
|
49
|
+
tectonic_engine(engine).trigger_earthquake(plate_id: plate_id, magnitude: magnitude)
|
|
50
|
+
rescue ArgumentError => e
|
|
51
|
+
{ success: false, error: e.message }
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def tectonic_status(engine: nil, **)
|
|
55
|
+
eng = tectonic_engine(engine)
|
|
56
|
+
report = eng.tectonic_report
|
|
57
|
+
{ success: true }.merge(report)
|
|
58
|
+
rescue ArgumentError => e
|
|
59
|
+
{ success: false, error: e.message }
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
private
|
|
63
|
+
|
|
64
|
+
def tectonic_engine(engine)
|
|
65
|
+
engine || @tectonic_engine ||= Helpers::TectonicEngine.new
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'securerandom'
|
|
4
|
+
|
|
5
|
+
require 'legion/extensions/cognitive_tectonics/version'
|
|
6
|
+
require 'legion/extensions/cognitive_tectonics/helpers/constants'
|
|
7
|
+
require 'legion/extensions/cognitive_tectonics/helpers/belief_plate'
|
|
8
|
+
require 'legion/extensions/cognitive_tectonics/helpers/seismic_event'
|
|
9
|
+
require 'legion/extensions/cognitive_tectonics/helpers/tectonic_engine'
|
|
10
|
+
require 'legion/extensions/cognitive_tectonics/runners/cognitive_tectonics'
|
|
11
|
+
require 'legion/extensions/cognitive_tectonics/client'
|
|
12
|
+
|
|
13
|
+
module Legion
|
|
14
|
+
module Extensions
|
|
15
|
+
module CognitiveTectonics
|
|
16
|
+
extend Legion::Extensions::Core if Legion::Extensions.const_defined? :Core
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: lex-cognitive-tectonics
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Esity
|
|
8
|
+
bindir: bin
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: legion-gaia
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - ">="
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: '0'
|
|
19
|
+
type: :development
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - ">="
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: '0'
|
|
26
|
+
description: Tectonic belief-plate model for LegionIO — conviction as mass, drift
|
|
27
|
+
vectors, convergent/divergent/transform boundaries, seismic belief shifts, and aftershock
|
|
28
|
+
cascades
|
|
29
|
+
email:
|
|
30
|
+
- matthewdiverson@gmail.com
|
|
31
|
+
executables: []
|
|
32
|
+
extensions: []
|
|
33
|
+
extra_rdoc_files: []
|
|
34
|
+
files:
|
|
35
|
+
- ".github/workflows/ci.yml"
|
|
36
|
+
- ".gitignore"
|
|
37
|
+
- ".rspec"
|
|
38
|
+
- ".rubocop.yml"
|
|
39
|
+
- CLAUDE.md
|
|
40
|
+
- Gemfile
|
|
41
|
+
- README.md
|
|
42
|
+
- lex-cognitive-tectonics.gemspec
|
|
43
|
+
- lib/legion/extensions/cognitive_tectonics.rb
|
|
44
|
+
- lib/legion/extensions/cognitive_tectonics/actors/drift_tick.rb
|
|
45
|
+
- lib/legion/extensions/cognitive_tectonics/client.rb
|
|
46
|
+
- lib/legion/extensions/cognitive_tectonics/helpers/belief_plate.rb
|
|
47
|
+
- lib/legion/extensions/cognitive_tectonics/helpers/constants.rb
|
|
48
|
+
- lib/legion/extensions/cognitive_tectonics/helpers/seismic_event.rb
|
|
49
|
+
- lib/legion/extensions/cognitive_tectonics/helpers/tectonic_engine.rb
|
|
50
|
+
- lib/legion/extensions/cognitive_tectonics/runners/cognitive_tectonics.rb
|
|
51
|
+
- lib/legion/extensions/cognitive_tectonics/version.rb
|
|
52
|
+
homepage: https://github.com/LegionIO/lex-cognitive-tectonics
|
|
53
|
+
licenses:
|
|
54
|
+
- MIT
|
|
55
|
+
metadata:
|
|
56
|
+
homepage_uri: https://github.com/LegionIO/lex-cognitive-tectonics
|
|
57
|
+
source_code_uri: https://github.com/LegionIO/lex-cognitive-tectonics
|
|
58
|
+
documentation_uri: https://github.com/LegionIO/lex-cognitive-tectonics
|
|
59
|
+
changelog_uri: https://github.com/LegionIO/lex-cognitive-tectonics
|
|
60
|
+
bug_tracker_uri: https://github.com/LegionIO/lex-cognitive-tectonics/issues
|
|
61
|
+
rubygems_mfa_required: 'true'
|
|
62
|
+
rdoc_options: []
|
|
63
|
+
require_paths:
|
|
64
|
+
- lib
|
|
65
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
66
|
+
requirements:
|
|
67
|
+
- - ">="
|
|
68
|
+
- !ruby/object:Gem::Version
|
|
69
|
+
version: '3.4'
|
|
70
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
71
|
+
requirements:
|
|
72
|
+
- - ">="
|
|
73
|
+
- !ruby/object:Gem::Version
|
|
74
|
+
version: '0'
|
|
75
|
+
requirements: []
|
|
76
|
+
rubygems_version: 3.6.9
|
|
77
|
+
specification_version: 4
|
|
78
|
+
summary: LEX Cognitive Tectonics
|
|
79
|
+
test_files: []
|