legion-gaia 0.9.57 → 0.9.58
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 +4 -4
- data/.rubocop.yml +1 -1
- data/AGENTS.md +55 -0
- data/CHANGELOG.md +4 -0
- data/CLAUDE.md +77 -180
- data/README.md +238 -81
- data/lib/legion/gaia/bond_registry.rb +228 -39
- data/lib/legion/gaia/bond_store.rb +299 -0
- data/lib/legion/gaia/bond_tracker.rb +54 -0
- data/lib/legion/gaia/cognitive_bus.rb +239 -0
- data/lib/legion/gaia/settings.rb +12 -11
- data/lib/legion/gaia/version.rb +1 -1
- data/lib/legion/gaia.rb +70 -6
- metadata +5 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b1f027ab3c8daed0ec4d1721c3c88e3efc15e475f1cb24f7999ba057074c9554
|
|
4
|
+
data.tar.gz: 1fdc0ccfe37b653d78eec31c0b1dce6b4294235c573af402d2b8205712c2fe0a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: cd0989a7ede3408c63a68b7f16a41bb6dc99c964d78811c1620d6caf50885a5c2ebed14ab7d6a90cdc7805ab99abd602469cecda522bb83a427d6e2667b6efae
|
|
7
|
+
data.tar.gz: 516b2c3d3defd7a2bc20e51693ffc053a82b2add2b4e709139e86b2d033a4b163dcef61d89548e0ac4edb0a2169c7a33dce5275b79c905262e1c3318366f0f31
|
data/.rubocop.yml
CHANGED
data/AGENTS.md
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# legion-gaia — Agent Notes
|
|
2
|
+
|
|
3
|
+
`legion-gaia` is the **cognitive coordination layer** of the LegionIO framework: a continuously
|
|
4
|
+
ticking agent runtime. It drains channel input (CLI, Microsoft Teams, Slack, HTTP) into a sensory
|
|
5
|
+
buffer, runs each heartbeat through a weighted pipeline of agentic cognitive phases via `lex-tick`,
|
|
6
|
+
and routes responses back out through schedule/presence/behavioral notification gates. See `CLAUDE.md`
|
|
7
|
+
for the file map and invariants; `README.md` for the user-facing tour.
|
|
8
|
+
|
|
9
|
+
## Fast Start
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
bundle install
|
|
13
|
+
bundle exec rspec # 0 failures required before commit
|
|
14
|
+
bundle exec rubocop # 0 offenses required
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Run **both** in full and fix everything before committing.
|
|
18
|
+
|
|
19
|
+
## Primary Entry Points
|
|
20
|
+
|
|
21
|
+
- `lib/legion/gaia.rb` — facade (`boot`, `ingest`, `heartbeat`, `respond`, `status`, `shutdown`)
|
|
22
|
+
- `lib/legion/gaia/phase_wiring.rb` — `PHASE_MAP` (37 phases: 16 active + 21 dream) + `PHASE_ARGS`
|
|
23
|
+
- `lib/legion/gaia/registry.rb` — extension discovery, runner wiring, phase-handler management
|
|
24
|
+
- `lib/legion/gaia/actors/heartbeat.rb` — the periodic drain → tick actor
|
|
25
|
+
- `lib/legion/gaia/notification_gate.rb` + `notification_gate/` — schedule / presence / behavioral gating
|
|
26
|
+
- `lib/legion/gaia/channels/` — `CliAdapter`, `TeamsAdapter`, `SlackAdapter` (+ auth/webhook/signing)
|
|
27
|
+
- `lib/legion/gaia/router/` — hub-and-spoke `RouterBridge` / `AgentBridge` / `WorkerRouting`
|
|
28
|
+
- `lib/legion/gaia/routes.rb` — self-registering `/api/gaia/*` Sinatra routes
|
|
29
|
+
- `lib/legion/gaia/settings.rb` — `Settings.default`, the config schema
|
|
30
|
+
|
|
31
|
+
## Guardrails / Gotchas (these prevent real bugs)
|
|
32
|
+
|
|
33
|
+
- **`lex-tick` is mandatory** — GAIA cannot run a tick without it; the heartbeat degrades gracefully
|
|
34
|
+
(warns once, retries) when the tick runner is unresolvable.
|
|
35
|
+
- **37 phases, not all always active** — phases whose runner extension isn't loaded are skipped at
|
|
36
|
+
wiring time. Every phase result must carry `status` (`completed`/`skipped`/`failed`) and
|
|
37
|
+
`elapsed_ms`; the `/api/gaia/ticks` stream depends on it.
|
|
38
|
+
- **Channel adapters are thin and stateless** — translate format only, no business logic, no state,
|
|
39
|
+
recreatable without loss. Every channel authenticates identity before input reaches GAIA
|
|
40
|
+
(Teams JWT/Bot Framework, Slack HMAC-SHA256).
|
|
41
|
+
- **Notification gate order is schedule → presence → behavioral**; critical/urgent priority bypasses
|
|
42
|
+
all layers. Delayed frames sit in a bounded `DelayQueue` re-evaluated each heartbeat.
|
|
43
|
+
- **Router mode** (`boot(mode: :router)`) boots channels only — no SensoryBuffer/cognitive
|
|
44
|
+
extensions. Worker allowlists are enforced for live registration and DB-backed resolution.
|
|
45
|
+
- **Shutdown is quiescing** — new heartbeats blocked, in-flight work drained, phase handlers return
|
|
46
|
+
`{ status: :skipped, reason: :gaia_shutting_down }`; never let teardown write into closed services.
|
|
47
|
+
- **`Legion::JSON` only** (symbol keys); inside `Legion::`, `::JSON`/`::Process` must be explicit.
|
|
48
|
+
Every `rescue` re-raises or `handle_exception`s; use `log.*`, never `puts`.
|
|
49
|
+
- **No personal/company identifiers in VCS**; never force-push.
|
|
50
|
+
- Settings merge is **deep** (`Legion::Settings[:gaia]` over `Settings.default`) — mutate nested keys.
|
|
51
|
+
|
|
52
|
+
## Validation
|
|
53
|
+
|
|
54
|
+
Run targeted specs for the area you touched (`spec/legion/gaia/...`), then full `rspec` + `rubocop`
|
|
55
|
+
before handoff. The suite runs in-process without external infrastructure.
|
data/CHANGELOG.md
CHANGED
data/CLAUDE.md
CHANGED
|
@@ -1,190 +1,87 @@
|
|
|
1
|
-
# legion-gaia
|
|
1
|
+
# legion-gaia
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
-
|
|
6
|
-
-
|
|
3
|
+
Cognitive coordination layer for LegionIO — a continuously ticking agent runtime. Drains channel
|
|
4
|
+
input into a sensory buffer, runs it through a weighted pipeline of agentic cognitive phases via
|
|
5
|
+
`lex-tick`, and routes responses back out through schedule/presence/behavioral notification gates.
|
|
6
|
+
Provides channel abstraction for multi-interface communication (CLI, Microsoft Teams, Slack).
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
**GitHub**: https://github.com/LegionIO/legion-gaia
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
## Build & Test
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
lib/legion/gaia/version.rb # VERSION constant
|
|
17
|
-
lib/legion/gaia/settings.rb # Default config hash (channels, router, session, output)
|
|
18
|
-
lib/legion/gaia/registry.rb # Extension discovery, runner wiring, phase handler management
|
|
19
|
-
lib/legion/gaia/phase_wiring.rb # PHASE_MAP (25 phases: 16 active + 9 dream), PHASE_ARGS, resolve/build helpers
|
|
20
|
-
lib/legion/gaia/runner_host.rb # Wraps runner modules with isolated instance state via extend
|
|
21
|
-
lib/legion/gaia/sensory_buffer.rb # Thread-safe signal queue (max 1000, normalized)
|
|
22
|
-
lib/legion/gaia/actors/heartbeat.rb # Every-1s actor, drains buffer and drives tick
|
|
23
|
-
lib/legion/gaia/input_frame.rb # Data.define — immutable inbound message from any channel
|
|
24
|
-
lib/legion/gaia/output_frame.rb # Data.define — immutable outbound response to any channel
|
|
25
|
-
lib/legion/gaia/channel_adapter.rb # Base class for channel adapters (translate in/out, deliver)
|
|
26
|
-
lib/legion/gaia/channel_registry.rb # Registry of active channel adapters, thread-safe
|
|
27
|
-
lib/legion/gaia/channel_aware_renderer.rb # Adapts output complexity to channel capabilities + transition suggestions
|
|
28
|
-
lib/legion/gaia/output_router.rb # Routes OutputFrames through renderer to correct adapter
|
|
29
|
-
lib/legion/gaia/session_store.rb # Session continuity tracking, keyed by human identity
|
|
30
|
-
lib/legion/gaia/channels/cli_adapter.rb # First concrete adapter — wraps CLI input/output
|
|
31
|
-
lib/legion/gaia/channels/teams_adapter.rb # Teams adapter — Bot Framework activities to Frames
|
|
32
|
-
lib/legion/gaia/channels/teams/bot_framework_auth.rb # JWT validation for Bot Framework tokens
|
|
33
|
-
lib/legion/gaia/channels/teams/conversation_store.rb # Thread-safe conversation reference storage
|
|
34
|
-
lib/legion/gaia/channels/teams/webhook_handler.rb # HTTP webhook handler for Bot Framework activities
|
|
35
|
-
lib/legion/gaia/channels/slack_adapter.rb # Slack adapter — Events API to Frames
|
|
36
|
-
lib/legion/gaia/channels/slack/signing_verifier.rb # HMAC-SHA256 request verification for Slack Events API
|
|
37
|
-
lib/legion/gaia/router.rb # Router module entry point, conditional transport loading
|
|
38
|
-
lib/legion/gaia/router/worker_routing.rb # Identity-to-worker routing table with allowlist
|
|
39
|
-
lib/legion/gaia/router/router_bridge.rb # Central router: inbound routing + outbound delivery
|
|
40
|
-
lib/legion/gaia/router/agent_bridge.rb # Agent-side: subscribe inbound, publish outbound
|
|
41
|
-
lib/legion/gaia/router/transport/exchanges/gaia.rb # Topic exchange for GAIA outbound frames
|
|
42
|
-
lib/legion/gaia/router/transport/queues/inbound.rb # Per-worker inbound queue (subclass of Transport::Queues::Agent)
|
|
43
|
-
lib/legion/gaia/router/transport/queues/outbound.rb # Shared outbound queue (agent->router)
|
|
44
|
-
lib/legion/gaia/router/transport/messages/input_frame_message.rb # InputFrame -> RabbitMQ
|
|
45
|
-
lib/legion/gaia/router/transport/messages/output_frame_message.rb # OutputFrame -> RabbitMQ
|
|
46
|
-
lib/legion/gaia/notification_gate.rb # Three-layer gate between OutputRouter and delivery
|
|
47
|
-
lib/legion/gaia/notification_gate/schedule_evaluator.rb # Config-driven quiet hours (day/time/timezone windows)
|
|
48
|
-
lib/legion/gaia/notification_gate/presence_evaluator.rb # Teams presence status -> priority threshold mapping
|
|
49
|
-
lib/legion/gaia/notification_gate/behavioral_evaluator.rb # Learned signal scoring (arousal, idle time)
|
|
50
|
-
lib/legion/gaia/notification_gate/delay_queue.rb # Thread-safe delayed message queue (max size, TTL)
|
|
51
|
-
lib/legion/gaia/proactive.rb # Proactive message delivery: send_message, broadcast to channels
|
|
52
|
-
lib/legion/gaia/offline_handler.rb # Offline agent handling: queue messages, notify sender, presence tracking
|
|
12
|
+
```bash
|
|
13
|
+
bundle install
|
|
14
|
+
bundle exec rspec # 0 failures required before commit
|
|
15
|
+
bundle exec rubocop # 0 offenses required
|
|
53
16
|
```
|
|
54
17
|
|
|
55
|
-
##
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
- `WebhookHandler` routes inbound activities by type: message, conversationUpdate, invoke, other
|
|
80
|
-
- Bot @mention stripping ensures clean text reaches the cognitive pipeline
|
|
81
|
-
- Mobile/desktop device detection from `channelData.clientInfo.platform`
|
|
82
|
-
- Delivery uses `lex-microsoft_teams` Bot runner (`send_text`/`send_card`) when available
|
|
83
|
-
- Teams adapter auto-registers during `boot_channels` when `channels.teams.enabled` is true
|
|
18
|
+
## Where Things Live (most-touched)
|
|
19
|
+
|
|
20
|
+
| Path | Purpose |
|
|
21
|
+
|------|---------|
|
|
22
|
+
| `lib/legion/gaia.rb` | Facade: `boot`, `ingest`, `heartbeat`, `respond`, `status`, `shutdown`; heartbeat quiescence, partner-absence and proactive logic |
|
|
23
|
+
| `lib/legion/gaia/phase_wiring.rb` | `PHASE_MAP` (37 phases: 16 active + 21 dream), `PHASE_ARGS` lambdas, runner resolution, phase-result annotation |
|
|
24
|
+
| `lib/legion/gaia/registry.rb` | Extension discovery, runner wiring, phase-handler management (singleton via `Registry.instance`) |
|
|
25
|
+
| `lib/legion/gaia/runner_host.rb` | Extends a runner module onto an instance so modules get persistent `@ivar` state |
|
|
26
|
+
| `lib/legion/gaia/sensory_buffer.rb` | Thread-safe bounded signal queue (`MAX_BUFFER_SIZE`) |
|
|
27
|
+
| `lib/legion/gaia/actors/heartbeat.rb` | Periodic actor: drain buffer → tick |
|
|
28
|
+
| `lib/legion/gaia/input_frame.rb` / `output_frame.rb` | `Data.define` immutable channel frames |
|
|
29
|
+
| `lib/legion/gaia/channel_adapter.rb` | Base class: `translate_inbound` / `translate_outbound` / `deliver`; `adapter_classes` registry |
|
|
30
|
+
| `lib/legion/gaia/channel_registry.rb` | Active adapters; thread-safe register/unregister/deliver |
|
|
31
|
+
| `lib/legion/gaia/channel_aware_renderer.rb` | Adapts content complexity to channel limits + transition suggestions |
|
|
32
|
+
| `lib/legion/gaia/output_router.rb` | Chains renderer → notification gate → registry → adapter |
|
|
33
|
+
| `lib/legion/gaia/notification_gate.rb` + `notification_gate/` | Schedule / presence / behavioral evaluators + bounded `DelayQueue` |
|
|
34
|
+
| `lib/legion/gaia/session_store.rb` | Session continuity keyed by human identity, TTL-based |
|
|
35
|
+
| `lib/legion/gaia/router/` | Hub-and-spoke for multi-worker deployments: `WorkerRouting`, `RouterBridge`, `AgentBridge` |
|
|
36
|
+
| `lib/legion/gaia/channels/` | `CliAdapter`, `TeamsAdapter` (+ `teams/` auth/webhook), `SlackAdapter` (+ `slack/` signing) |
|
|
37
|
+
| `lib/legion/gaia/routes.rb` | Self-registering Sinatra routes under `/api/gaia/*` and `/api/channels/teams/webhook` |
|
|
38
|
+
| `lib/legion/gaia/settings.rb` | `Settings.default` — the config schema |
|
|
39
|
+
| `lib/legion/gaia/version.rb` | `VERSION` constant (source of truth for the published gem) |
|
|
40
|
+
|
|
41
|
+
## Data Flow
|
|
84
42
|
|
|
85
|
-
### Phase 4: Central Router (Hub-and-Spoke)
|
|
86
|
-
- Dual boot modes: `Legion::Gaia.boot(mode: :router)` for stateless router, default `:agent` for full GAIA
|
|
87
|
-
- Router mode: boots channels only — no SensoryBuffer, Registry, or cognitive extensions
|
|
88
|
-
- `RouterBridge` handles inbound routing (identity -> worker_id -> RabbitMQ queue) and outbound delivery
|
|
89
|
-
- `AgentBridge` subscribes to per-worker inbound queue, pushes InputFrames into local GAIA SensoryBuffer
|
|
90
|
-
- `AgentBridge` publishes OutputFrames to outbound queue when `respond` is called
|
|
91
|
-
- `WorkerRouting` maps Entra OID / identity to worker_id with allowlist enforcement
|
|
92
|
-
- Transport layer follows standard legion-transport patterns (Exchange, Queue, Message base classes)
|
|
93
|
-
- Inbound uses the `agent` exchange (from `legion-transport`): routing key `agent.<worker_id>`, queue `agent.<worker_id>` (via `Transport::Queues::Agent`). Outbound uses the `gaia` exchange (many-to-one fan-in to router).
|
|
94
|
-
- Transport classes only loaded when `legion-transport` is available (conditional require)
|
|
95
|
-
- Router never sees cognitive state — only InputFrame/OutputFrame envelopes
|
|
96
|
-
|
|
97
|
-
### Phase 5: Slack Adapter + Cross-Channel Polish
|
|
98
|
-
- `SlackAdapter` translates Slack Events API payloads to InputFrames and OutputFrames to Slack messages
|
|
99
|
-
- `SigningVerifier` validates inbound requests via HMAC-SHA256 (signing secret + timestamp + body)
|
|
100
|
-
- Bot `<@UBOT>` mention stripping for clean text input
|
|
101
|
-
- Thread-aware outbound delivery (preserves `thread_ts` for reply threading)
|
|
102
|
-
- Slack adapter auto-registers during `boot_channels` when `channels.slack.enabled` is true
|
|
103
|
-
- `ChannelAwareRenderer` adds transition suggestions when content is truncated (e.g., "Full response available on cli")
|
|
104
|
-
- Richness hierarchy: voice -> slack -> cli (richer channels suggested when content exceeds limits)
|
|
105
|
-
|
|
106
|
-
### Phase 6: Notification Gate
|
|
107
|
-
- `NotificationGate` sits between OutputRouter and channel delivery, evaluating each frame
|
|
108
|
-
- Three evaluation layers in order: schedule (quiet hours) -> presence (Teams status) -> behavioral (learned signals)
|
|
109
|
-
- `ScheduleEvaluator` parses config-driven schedule arrays with day/time/timezone windows, handles overnight wraps
|
|
110
|
-
- `PresenceEvaluator` maps Teams availability states to minimum priority thresholds (Available->ambient, Busy/Away->urgent, DoNotDisturb/Offline->critical)
|
|
111
|
-
- `BehavioralEvaluator` uses arousal (0.0-1.0) and idle_seconds signals to compute notification score
|
|
112
|
-
- Priority override: critical/urgent messages bypass all layers
|
|
113
|
-
- `DelayQueue` is thread-safe with mutex, max_size eviction, TTL-based expiration, flush
|
|
114
|
-
- OutputRouter calls `notification_gate.evaluate(frame)` -> `:deliver` or `:delay`
|
|
115
|
-
- Delayed frames re-evaluated each heartbeat tick via `process_delayed` (drain expired, flush when quiet ends)
|
|
116
|
-
|
|
117
|
-
### Data Flow
|
|
118
43
|
```
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
Heartbeat tick
|
|
122
|
-
|
|
123
|
-
Cognitive
|
|
44
|
+
Channel input -> ChannelAdapter#translate_inbound -> InputFrame -> Gaia.ingest -> SensoryBuffer
|
|
45
|
+
|
|
|
46
|
+
Heartbeat tick (lex-tick)
|
|
47
|
+
|
|
|
48
|
+
Cognitive output <- OutputFrame <- OutputRouter <- NotificationGate <- ChannelAdapter#deliver
|
|
124
49
|
```
|
|
125
50
|
|
|
126
|
-
##
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
- `
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
| `lex-agentic-affect` | Affective processing domain (emotional_evaluation, gut_instinct phases) |
|
|
164
|
-
| `lex-agentic-attention` | Attention management domain (sensory_processing phase) |
|
|
165
|
-
| `lex-agentic-defense` | Defense and threat response domain |
|
|
166
|
-
| `lex-agentic-executive` | Executive function and goal management (action_selection phase) |
|
|
167
|
-
| `lex-agentic-homeostasis` | Internal state regulation (homeostasis_regulation phase) |
|
|
168
|
-
| `lex-agentic-imagination` | Creative and hypothetical reasoning |
|
|
169
|
-
| `lex-agentic-inference` | Probabilistic inference domain (prediction_engine phase) |
|
|
170
|
-
| `lex-agentic-integration` | Sensory integration domain |
|
|
171
|
-
| `lex-agentic-language` | Language processing domain (dream_narration phase) |
|
|
172
|
-
| `lex-agentic-learning` | Learning and adaptation domain |
|
|
173
|
-
| `lex-agentic-memory` | Memory management domain (memory_retrieval, memory_consolidation, dream cycle phases) |
|
|
174
|
-
| `lex-agentic-self` | Self-model and identity domain (identity_entropy_check phase) |
|
|
175
|
-
| `lex-agentic-social` | Social cognition domain (social_cognition, theory_of_mind phases) |
|
|
176
|
-
|
|
177
|
-
### Optional at runtime (not declared in gemspec)
|
|
178
|
-
|
|
179
|
-
- `legion-transport` — required for router mode (hub-and-spoke), conditional require
|
|
180
|
-
- `lex-microsoft_teams` — required for Teams delivery, guarded
|
|
181
|
-
- Other agentic LEXs are discovered via `Legion::Extensions`
|
|
182
|
-
|
|
183
|
-
## Future
|
|
184
|
-
|
|
185
|
-
- Voice adapter
|
|
186
|
-
- Proactive notification scheduling (agent-initiated messages at optimal delivery times)
|
|
187
|
-
|
|
188
|
-
---
|
|
189
|
-
|
|
190
|
-
**Maintained By**: Matthew Iverson (@Esity)
|
|
51
|
+
## HTTP Routes (`routes.rb`)
|
|
52
|
+
|
|
53
|
+
`GET /api/gaia/status`, `GET /api/gaia/ticks`, `GET /api/gaia/channels`, `GET /api/gaia/buffer`,
|
|
54
|
+
`GET /api/gaia/sessions`, `POST /api/gaia/ingest`, `POST /api/channels/teams/webhook`. Registered via
|
|
55
|
+
`Legion::API.register_library_routes('gaia', Legion::Gaia::Routes)` at boot.
|
|
56
|
+
|
|
57
|
+
## Gotchas / Invariants (these prevent real bugs)
|
|
58
|
+
|
|
59
|
+
- **`lex-tick` is mandatory** — GAIA is inoperable without the tick orchestrator. The heartbeat
|
|
60
|
+
degrades gracefully if the tick runner is unresolvable (warns once, retries next tick).
|
|
61
|
+
- **Phase counts**: `PHASE_MAP` is 37 entries — 16 active-tick, 21 dream-cycle. Phases whose runner
|
|
62
|
+
extension isn't loaded are skipped at wiring time; don't assume every phase is always active.
|
|
63
|
+
- **Every phase result is annotated** with `status` (`completed`/`skipped`/`failed`) and `elapsed_ms`
|
|
64
|
+
(monotonic). The `/api/gaia/ticks` stream depends on these always being present.
|
|
65
|
+
- **Frames are immutable** — `InputFrame`/`OutputFrame` are `Data.define`, frozen, pattern-matchable.
|
|
66
|
+
- **Channel adapters are thin and stateless** — translate format only, no business logic, no state;
|
|
67
|
+
they must be recreatable without loss. Authentication is non-negotiable: every channel validates
|
|
68
|
+
identity before input reaches GAIA (Teams JWT/Bot Framework, Slack HMAC-SHA256).
|
|
69
|
+
- **Critical/urgent priority bypasses all notification-gate layers.** Gate order is schedule →
|
|
70
|
+
presence → behavioral.
|
|
71
|
+
- **Router mode** (`boot(mode: :router)`) boots channels only — no SensoryBuffer or cognitive
|
|
72
|
+
extensions. Worker allowlists are enforced for live registrations *and* DB-backed resolution.
|
|
73
|
+
- **Quiescing shutdown** — once `shutdown` starts, phase handlers return
|
|
74
|
+
`{ status: :skipped, reason: :gaia_shutting_down }`; new heartbeats are blocked and in-flight work
|
|
75
|
+
drains (bounded by `shutdown.heartbeat_wait_timeout`). This prevents late writes to closed services.
|
|
76
|
+
- **Transport classes load conditionally** — only required when `legion-transport` is available.
|
|
77
|
+
- **Settings merge is deep** — `Legion::Gaia.settings` deep-merges `Legion::Settings[:gaia]` over
|
|
78
|
+
`Settings.default`; mutate nested keys, don't replace the whole hash.
|
|
79
|
+
|
|
80
|
+
## Legion-Wide Rules
|
|
81
|
+
|
|
82
|
+
- **`Legion::JSON` only** — `Legion::JSON.load` returns **symbol keys**; `.dump` takes exactly one
|
|
83
|
+
positional arg. Inside the `Legion::` namespace, `::JSON` and `::Process` must be explicit.
|
|
84
|
+
- **Never swallow exceptions** — every `rescue` re-raises or calls `handle_exception(e, level:,
|
|
85
|
+
operation:)`. Use `log.*` (via `Legion::Gaia::Logging` / `Legion::Logging::Helper`), never `puts`.
|
|
86
|
+
- **No personal/company identifiers in VCS.** Never force-push.
|
|
87
|
+
- Ruby 3.4+, single quotes, frozen string literals, line length ≤ 120 (see `.rubocop.yml`).
|