@mindot/will 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.
Files changed (178) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +777 -0
  3. package/dist/index.d.ts +8144 -0
  4. package/dist/index.js +26231 -0
  5. package/dist/index.js.map +1 -0
  6. package/package.json +73 -0
  7. package/src/cognition/agency/access.grants.ts +59 -0
  8. package/src/cognition/agency/competence.codec.ts +89 -0
  9. package/src/cognition/agency/engines/action.selector.ts +462 -0
  10. package/src/cognition/agency/engines/affordance.synthesizer.ts +384 -0
  11. package/src/cognition/agency/engines/deliberation.engine.ts +241 -0
  12. package/src/cognition/agency/engines/instruction.intake.ts +54 -0
  13. package/src/cognition/agency/engines/motor.schema.executor.ts +532 -0
  14. package/src/cognition/agency/engines/reafference.engine.ts +241 -0
  15. package/src/cognition/agency/execution.primitives.ts +118 -0
  16. package/src/cognition/agency/index.ts +58 -0
  17. package/src/cognition/agency/proactive.communicator.ts +274 -0
  18. package/src/cognition/agency/reconcile.learning.ts +82 -0
  19. package/src/cognition/agency/schemas/external.ts +59 -0
  20. package/src/cognition/agency/schemas/innate.ts +111 -0
  21. package/src/cognition/agency/schemas/repertoire.ts +246 -0
  22. package/src/cognition/agency/selection.scoring.ts +191 -0
  23. package/src/cognition/agency/types.ts +165 -0
  24. package/src/cognition/bus.ts +391 -0
  25. package/src/cognition/completion.inbox.ts +86 -0
  26. package/src/cognition/config.mirror.entities.ts +475 -0
  27. package/src/cognition/conversation.memory.ts +81 -0
  28. package/src/cognition/event.log.ts +116 -0
  29. package/src/cognition/event.schemas.ts +568 -0
  30. package/src/cognition/faculties/aesthetic.evaluator.ts +313 -0
  31. package/src/cognition/faculties/affective.blender.ts +562 -0
  32. package/src/cognition/faculties/attachment.evaluator.ts +432 -0
  33. package/src/cognition/faculties/attention.allocator.ts +422 -0
  34. package/src/cognition/faculties/autobiographical.narrator.ts +300 -0
  35. package/src/cognition/faculties/bias.detector.ts +363 -0
  36. package/src/cognition/faculties/circadian.oscillator.ts +294 -0
  37. package/src/cognition/faculties/confidence.calibrator.ts +324 -0
  38. package/src/cognition/faculties/dream.simulator.ts +251 -0
  39. package/src/cognition/faculties/empathy.simulator.ts +253 -0
  40. package/src/cognition/faculties/energy.regulator.ts +320 -0
  41. package/src/cognition/faculties/episodic.consolidator.ts +728 -0
  42. package/src/cognition/faculties/executive.engine/commands.ts +459 -0
  43. package/src/cognition/faculties/executive.engine/config.ts +46 -0
  44. package/src/cognition/faculties/executive.engine/context.ts +605 -0
  45. package/src/cognition/faculties/executive.engine/deferred.effects.ts +104 -0
  46. package/src/cognition/faculties/executive.engine/deliberate.reasoning.ts +60 -0
  47. package/src/cognition/faculties/executive.engine/effort.gate.ts +114 -0
  48. package/src/cognition/faculties/executive.engine/engine.ts +1028 -0
  49. package/src/cognition/faculties/executive.engine/escalation.buffer.ts +90 -0
  50. package/src/cognition/faculties/executive.engine/facet.supervisor.ts +271 -0
  51. package/src/cognition/faculties/executive.engine/facet.ts +628 -0
  52. package/src/cognition/faculties/executive.engine/gating.ts +222 -0
  53. package/src/cognition/faculties/executive.engine/index.ts +6 -0
  54. package/src/cognition/faculties/executive.engine/messages.ts +102 -0
  55. package/src/cognition/faculties/executive.engine/parser.ts +380 -0
  56. package/src/cognition/faculties/executive.engine/prompt.factory.ts +1053 -0
  57. package/src/cognition/faculties/executive.engine/types.ts +323 -0
  58. package/src/cognition/faculties/exteroception.ts +338 -0
  59. package/src/cognition/faculties/forgetting.curve.ts +202 -0
  60. package/src/cognition/faculties/frustration.evaluator.ts +280 -0
  61. package/src/cognition/faculties/goal.manager.ts +1008 -0
  62. package/src/cognition/faculties/inhibition.controller.ts +351 -0
  63. package/src/cognition/faculties/interoception.ts +417 -0
  64. package/src/cognition/faculties/introspection.engine.ts +246 -0
  65. package/src/cognition/faculties/known.entity.tracker.ts +439 -0
  66. package/src/cognition/faculties/loss.evaluator.ts +224 -0
  67. package/src/cognition/faculties/moral.evaluator.ts +437 -0
  68. package/src/cognition/faculties/novelty.detector.ts +254 -0
  69. package/src/cognition/faculties/persona.consolidator.ts +845 -0
  70. package/src/cognition/faculties/planning.engine/engine.ts +859 -0
  71. package/src/cognition/faculties/planning.engine/plan.frontier.ts +83 -0
  72. package/src/cognition/faculties/planning.engine/plan.store.ts +174 -0
  73. package/src/cognition/faculties/planning.engine/plan.supervision.ts +494 -0
  74. package/src/cognition/faculties/planning.engine/types.ts +143 -0
  75. package/src/cognition/faculties/reputation.tracker.ts +294 -0
  76. package/src/cognition/faculties/reward.evaluator.ts +304 -0
  77. package/src/cognition/faculties/self.model.updater.ts +677 -0
  78. package/src/cognition/faculties/semantic.engine/clustering.ts +673 -0
  79. package/src/cognition/faculties/semantic.engine/index.ts +6 -0
  80. package/src/cognition/faculties/semantic.engine/integrator.ts +750 -0
  81. package/src/cognition/faculties/semantic.engine/types.ts +53 -0
  82. package/src/cognition/faculties/sleep.pressure.regulator.ts +262 -0
  83. package/src/cognition/faculties/social.perception.ts +333 -0
  84. package/src/cognition/faculties/spaced.repetition.ts +605 -0
  85. package/src/cognition/faculties/stress.regulator.ts +375 -0
  86. package/src/cognition/faculties/task.switcher.ts +239 -0
  87. package/src/cognition/faculties/theory.of.mind.ts +333 -0
  88. package/src/cognition/faculties/threat.evaluator.ts +312 -0
  89. package/src/cognition/faculties/working.memory.ts +406 -0
  90. package/src/cognition/generative.model.ts +344 -0
  91. package/src/cognition/heartbeat.ts +70 -0
  92. package/src/cognition/index.ts +291 -0
  93. package/src/cognition/instruction.handler.ts +146 -0
  94. package/src/cognition/memory/index.ts +35 -0
  95. package/src/cognition/memory/vector.adapter.ts +316 -0
  96. package/src/cognition/memory/vector.content.ts +47 -0
  97. package/src/cognition/memory/vector.embedder.ts +212 -0
  98. package/src/cognition/memory/vector.index.ts +459 -0
  99. package/src/cognition/memory/vector.types.ts +65 -0
  100. package/src/cognition/orchestrator.ts +142 -0
  101. package/src/cognition/persona.prior.ts +265 -0
  102. package/src/cognition/schema.registry.ts +145 -0
  103. package/src/cognition/senses/audition.engine/engine.ts +976 -0
  104. package/src/cognition/senses/audition.engine/salience.ts +59 -0
  105. package/src/cognition/senses/base.sense.engine.ts +117 -0
  106. package/src/cognition/senses/gustation.engine.ts +24 -0
  107. package/src/cognition/senses/index.ts +172 -0
  108. package/src/cognition/senses/olfaction.engine.ts +24 -0
  109. package/src/cognition/senses/somatosensation.engine.ts +23 -0
  110. package/src/cognition/senses/vision.engine.ts +23 -0
  111. package/src/cognition/types.ts +63 -0
  112. package/src/cognition/utilities/token.tracker.ts +492 -0
  113. package/src/core/abstracts.ts +60 -0
  114. package/src/core/async.engine.ts +539 -0
  115. package/src/core/clock.ts +196 -0
  116. package/src/core/completion.recorder.ts +122 -0
  117. package/src/core/conflict.detector.ts +140 -0
  118. package/src/core/distributed.ts +626 -0
  119. package/src/core/event.bus.ts +292 -0
  120. package/src/core/inbound.recorder.ts +100 -0
  121. package/src/core/index.ts +167 -0
  122. package/src/core/logger.ts +85 -0
  123. package/src/core/metrics.ts +107 -0
  124. package/src/core/orchestrator.ts +625 -0
  125. package/src/core/replay.ts +589 -0
  126. package/src/core/scenario.ts +120 -0
  127. package/src/core/serialization.ts +448 -0
  128. package/src/core/simulation.ts +197 -0
  129. package/src/core/snapshot.manager.ts +293 -0
  130. package/src/core/state.manager.ts +283 -0
  131. package/src/core/types.ts +274 -0
  132. package/src/core/utils.ts +82 -0
  133. package/src/core/wall.clock.ts +23 -0
  134. package/src/extensions/livestream.ext.ts +570 -0
  135. package/src/extensions/time.ext.ts +339 -0
  136. package/src/index.ts +91 -0
  137. package/src/llm/gate.ts +140 -0
  138. package/src/llm/index.ts +716 -0
  139. package/src/llm/summarizer.ts +170 -0
  140. package/src/llm/wire.contracts.ts +67 -0
  141. package/src/pma/eval.ts +651 -0
  142. package/src/pma/index.ts +1082 -0
  143. package/src/profiles/built-in.ts +7 -0
  144. package/src/profiles/companion.ts +28 -0
  145. package/src/profiles/company-brain.ts +54 -0
  146. package/src/profiles/customer-service.ts +30 -0
  147. package/src/profiles/game-npc.ts +20 -0
  148. package/src/profiles/index.ts +42 -0
  149. package/src/profiles/smart-home.ts +34 -0
  150. package/src/runners/coherence.runner.ts +49 -0
  151. package/src/runners/outreach.runner.ts +158 -0
  152. package/src/runners/social.runner.ts +182 -0
  153. package/src/runners/thin-shim.runner.ts +195 -0
  154. package/src/sdk/will.ts +334 -0
  155. package/src/stem/assembly.audit.ts +88 -0
  156. package/src/stem/distribution.ts +203 -0
  157. package/src/stem/guards/identity.coherence.ts +152 -0
  158. package/src/stem/guards/identity.guard.ts +227 -0
  159. package/src/stem/index.ts +1145 -0
  160. package/src/stem/mind.ts +1090 -0
  161. package/src/stem/tracts/ack.reconciler.ts +55 -0
  162. package/src/stem/tracts/biography.writer.ts +190 -0
  163. package/src/stem/tracts/effector.controller.ts +143 -0
  164. package/src/stem/tracts/health.reporter.ts +113 -0
  165. package/src/stem/tracts/inbound.queue.ts +54 -0
  166. package/src/stem/tracts/outbox.controller.ts +167 -0
  167. package/src/stem/tracts/outbox.writer.ts +133 -0
  168. package/src/stem/tracts/pma.controller.ts +109 -0
  169. package/src/stem/tracts/replay.controller.ts +177 -0
  170. package/src/stem/tracts/sensory.controller.ts +168 -0
  171. package/src/stem/tracts/session.logger.ts +157 -0
  172. package/src/stem/tracts/transport/index.ts +38 -0
  173. package/src/stem/tracts/transport/loopback.transport.ts +86 -0
  174. package/src/stem/tracts/transport/socketio.transport.ts +200 -0
  175. package/src/stem/tracts/transport/stream.transport.ts +152 -0
  176. package/src/stem/tracts/transport/types.ts +193 -0
  177. package/src/stem/tracts/transport.controller.ts +380 -0
  178. package/src/types.ts +116 -0
@@ -0,0 +1,320 @@
1
+ // ─────────────────────────────────────────────────────────────
2
+ // src/cognition/faculties/energy.regulator.ts
3
+ // ─────────────────────────────────────────────────────────────
4
+
5
+ /**
6
+ * EnergyRegulator — maintains the mind's energy pool.
7
+ *
8
+ * Energy decays continuously (cognitive work consumes resources).
9
+ * It replenishes during rest states or when external replenishment
10
+ * events occur. Depletion triggers hunger-like drive signals and
11
+ * degrades cognitive performance via modulation.
12
+ *
13
+ * NEW: Enforces hard system collapse when energy drops below 1.
14
+ * This is the biological equivalent of losing consciousness —
15
+ * the body forces recovery regardless of the Will's decisions.
16
+ * The forced rest state clears when energy recovers past 15.
17
+ *
18
+ * Part of Shard 0 (Regulatory Layer) — runs every tick, synchronous.
19
+ */
20
+
21
+ import { logger } from '#core/logger'
22
+ import type {
23
+ Duration,
24
+ Tick,
25
+ SimulationContext,
26
+ ReadonlySimulationState,
27
+ StateCommands,
28
+ SimulationEvent,
29
+ DriveSignal,
30
+ ModulationSignal,
31
+ } from '#core/types'
32
+ import type { SimulationEngine, EngineResult, CognitiveEngine } from '#cognition/types'
33
+ import type { CognitiveEventSchema } from '#cognition/schema.registry'
34
+ import type { CognitiveEvent, CognitiveBus } from '#cognition/bus'
35
+ import { GenerativeModel, type GenerativeModelSnapshot } from '#cognition/generative.model'
36
+
37
+ export interface EnergyRegulatorConfig {
38
+ maxEnergy?: number
39
+ baseDecayRate?: number
40
+ restReplenishRate?: number
41
+ lowEnergyThreshold?: number
42
+ criticalEnergyThreshold?: number
43
+ /** Energy level below which the system forces unconscious recovery */
44
+ collapseThreshold?: number
45
+ /** Energy level at which forced recovery ends and consciousness returns */
46
+ recoveryThreshold?: number
47
+ bus?: CognitiveBus
48
+ }
49
+
50
+ // ── Cognitive metabolic cost ──────────────────────────────────────────────────
51
+ // Being awake costs energy; attending to more (cognitive load) and voluntarily
52
+ // engaging harder (effort) cost more. This is the continuous counterpart to the
53
+ // `focus` effector's one-shot energyCost — it makes sustained focus self-limiting
54
+ // against the energy pool, closing the attention→energy half of the homeostatic
55
+ // loop (energy already caps the AttentionAllocator's capacity ceiling). Both
56
+ // inputs are read from SimulationState metrics, so they need no engine snapshot.
57
+ const LOAD_DECAY_GAIN = 0.5 // ×base decay per unit cognitive load (attention.usage, 0–1)
58
+ const EFFORT_DECAY_GAIN = 1.0 // ×base decay per unit effort above the homeostatic baseline
59
+ const EFFORT_BASELINE = 0.7 // attention's homeostatic effort set-point — cost-neutral
60
+ // (mirrors EFFORT_BASELINE in attention.allocator.ts)
61
+
62
+ export class EnergyRegulator implements SimulationEngine, CognitiveEngine {
63
+ readonly name = 'energy-regulator'
64
+
65
+ private _maxEnergy: number
66
+ private _baseDecayRate: number
67
+ private _restReplenishRate: number
68
+ private _lowThreshold: number
69
+ private _criticalThreshold: number
70
+ private _collapseThreshold: number
71
+ private _recoveryThreshold: number
72
+
73
+ private _bus: CognitiveBus | null = null
74
+
75
+ private readonly _model = new GenerativeModel()
76
+
77
+
78
+ constructor( config: EnergyRegulatorConfig = {} ){
79
+ this._bus = config.bus ?? null
80
+ this._maxEnergy = config.maxEnergy ?? 100
81
+ this._baseDecayRate = config.baseDecayRate ?? 0.02
82
+ this._restReplenishRate = config.restReplenishRate ?? 0.15
83
+ this._lowThreshold = config.lowEnergyThreshold ?? 30
84
+ this._criticalThreshold = config.criticalEnergyThreshold ?? 10
85
+ this._collapseThreshold = config.collapseThreshold ?? 1
86
+ this._recoveryThreshold = config.recoveryThreshold ?? 15
87
+ }
88
+ attachBus( bus: CognitiveBus ): void { this._bus = bus }
89
+
90
+
91
+ subscribes(): string[] { return ["executive.prediction.formed"] }
92
+ publishes(): CognitiveEventSchema[] { return [] }
93
+
94
+ onCognitiveEvent( e: CognitiveEvent ): StateCommands | void {
95
+ this._model.observe( e.type, e.salience )
96
+ if( e.type === 'executive.prediction.formed' ){
97
+ const p = e.payload as { predictedDomains: string[]; confidence: number }
98
+ if( p.predictedDomains.includes('energy') )
99
+ this._model.setPrecision( 'energy.level', 1.0 + p.confidence * 0.5 )
100
+ }
101
+ }
102
+
103
+ snapshot(): Record<string, unknown> {
104
+ // FN9: cognitive load + effort are now read from SimulationState metrics
105
+ // (already captured by the event-sourced state), and the activity multiplier
106
+ // is recomputed from them each tick — so the only durable engine-internal
107
+ // state left to capture is the GenerativeModel prediction baseline.
108
+ return { model: this._model.snapshot() }
109
+ }
110
+
111
+ restore( snap: Record<string, unknown> ): void {
112
+ if( !snap ) return
113
+ if( snap.model ) this._model.restore( snap.model as GenerativeModelSnapshot )
114
+ }
115
+
116
+ async react(
117
+ delta: Duration,
118
+ tick: Tick,
119
+ state: ReadonlySimulationState,
120
+ context: SimulationContext
121
+ ): Promise<EngineResult> {
122
+ this._readConfigFromState( state )
123
+
124
+ const
125
+ currentEnergy = state.metrics.get('energy.level') ?? this._maxEnergy,
126
+ isResting = state.metrics.get('state.resting') ?? 0,
127
+ isSleeping = state.metrics.get('state.sleeping') ?? 0,
128
+ isForcedRest = state.metrics.get('state.forced_rest') ?? 0,
129
+ // Cognitive load (how much is being attended) and voluntary effort (how hard
130
+ // the mind is engaging its capacity ceiling) are read straight from the
131
+ // attention metrics. effort's homeostatic baseline is cost-neutral; focusing
132
+ // above it burns the energy pool faster, standing down (rest) slower.
133
+ cognitiveLoad = state.metrics.get('attention.usage') ?? 0,
134
+ effort = state.metrics.get('attention.effort') ?? EFFORT_BASELINE,
135
+ events: Array<Omit<SimulationEvent, 'id' | 'timestamp' | 'tick'>> = [],
136
+ commands: StateCommands = { metrics: [] }
137
+
138
+ // Metabolic cost of cognition: cognitive load and sustained effort both raise
139
+ // the rate at which being awake drains energy. Clamped ≥ 0.5 so a calm, idle
140
+ // mind still ticks down at roughly half the base rate.
141
+ const activityMultiplier = Math.max(
142
+ 0.5,
143
+ 1.0 + cognitiveLoad * LOAD_DECAY_GAIN + ( effort - EFFORT_BASELINE ) * EFFORT_DECAY_GAIN
144
+ )
145
+
146
+ let newEnergy: number
147
+
148
+ // ── Forced rest (system collapse) — guaranteed recovery ──
149
+ if( isForcedRest > 0 || currentEnergy < this._collapseThreshold ){
150
+ // Body is forcing recovery. Energy always increases during forced rest.
151
+ // This is stronger than normal rest — the system is unconscious.
152
+ newEnergy = Math.min(
153
+ this._maxEnergy,
154
+ currentEnergy + this._restReplenishRate * 1.5 * ( delta / 1000 )
155
+ )
156
+
157
+ // Ensure forced_rest stays set
158
+ commands.metrics!.push([ 'state.forced_rest', 1 ])
159
+ commands.metrics!.push([ 'state.resting', 1 ])
160
+
161
+ // Clear forced rest when recovered past the recovery threshold
162
+ if( newEnergy >= this._recoveryThreshold ){
163
+ commands.metrics!.push([ 'state.forced_rest', 0 ])
164
+ commands.metrics!.push([ 'state.resting', 0 ])
165
+
166
+ events.push({
167
+ type: 'energy.consciousness_regained',
168
+ source: this.name,
169
+ payload: { energy: newEnergy, recoveryThreshold: this._recoveryThreshold },
170
+ })
171
+ }
172
+
173
+ // Periodic log during forced rest
174
+ if( tick % 100 === 0 ){
175
+ logger.info(`[energy] forced recovery — unconscious (energy=${newEnergy.toFixed(0)}, target=${this._recoveryThreshold})`)
176
+ }
177
+ }
178
+ // ── Voluntary rest or sleep ─────────────────────────────
179
+ else if( isSleeping > 0 ){
180
+ // Deep rest — rapid dissipation
181
+ newEnergy = Math.min(
182
+ this._maxEnergy,
183
+ currentEnergy + this._restReplenishRate * 2 * ( delta / 1000 )
184
+ )
185
+
186
+ if( currentEnergy < this._maxEnergy * 0.5 && newEnergy >= this._maxEnergy * 0.8 )
187
+ events.push({
188
+ type: 'energy.replenished',
189
+ source: this.name,
190
+ payload: { previous: currentEnergy, current: newEnergy },
191
+ })
192
+ }
193
+ else if( isResting > 0 ){
194
+ // Light rest — moderate dissipation
195
+ newEnergy = Math.min(
196
+ this._maxEnergy,
197
+ currentEnergy + this._restReplenishRate * ( delta / 1000 )
198
+ )
199
+
200
+ if( currentEnergy < this._maxEnergy * 0.5 && newEnergy >= this._maxEnergy * 0.8 )
201
+ events.push({
202
+ type: 'energy.replenished',
203
+ source: this.name,
204
+ payload: { previous: currentEnergy, current: newEnergy },
205
+ })
206
+ }
207
+ else {
208
+ // Awake — accumulate pressure
209
+ const decay = this._baseDecayRate * activityMultiplier * ( delta / 1000 )
210
+ const passiveRecovery = currentEnergy <= this._criticalThreshold
211
+ ? this._baseDecayRate * 0.5 * ( delta / 1000 )
212
+ : 0
213
+ newEnergy = Math.max( 0, currentEnergy - decay + passiveRecovery )
214
+
215
+ // ── System collapse event ───────────────────────────
216
+ if( currentEnergy > this._collapseThreshold && newEnergy <= this._collapseThreshold ){
217
+ events.push({
218
+ type: 'energy.system_collapse',
219
+ source: this.name,
220
+ payload: {
221
+ energy: newEnergy,
222
+ reason: 'Energy depleted below critical threshold. Body forcing recovery.',
223
+ collapseThreshold: this._collapseThreshold,
224
+ },
225
+ })
226
+
227
+ // Immediately enter forced rest
228
+ commands.metrics!.push([ 'state.forced_rest', 1 ])
229
+ commands.metrics!.push([ 'state.resting', 1 ])
230
+ }
231
+
232
+ // Critical depletion event
233
+ if( currentEnergy > this._criticalThreshold && newEnergy <= this._criticalThreshold )
234
+ events.push({
235
+ type: 'energy.critical',
236
+ source: this.name,
237
+ payload: { level: newEnergy, threshold: this._criticalThreshold },
238
+ })
239
+ }
240
+
241
+ // Clamp and store
242
+ newEnergy = Math.max( 0, Math.min( this._maxEnergy, newEnergy ) )
243
+ commands.metrics!.push([ 'energy.level', newEnergy ])
244
+
245
+ // ── Drive signal ──────────────────────────────────────
246
+ const
247
+ energyRatio = newEnergy / this._maxEnergy,
248
+ intensity = 1 - energyRatio,
249
+ urgency = newEnergy <= this._criticalThreshold
250
+ ? 1.0
251
+ : newEnergy <= this._lowThreshold
252
+ ? ( this._lowThreshold - newEnergy ) / ( this._lowThreshold - this._criticalThreshold )
253
+ : 0
254
+
255
+ const driveIntensity = Math.min( 1, Math.max( 0, intensity ) )
256
+ commands.metrics!.push([ 'drive.energy', driveIntensity ])
257
+
258
+ events.push({
259
+ type: 'drive.energy',
260
+ source: this.name,
261
+ payload: {
262
+ name: 'energy',
263
+ intensity: driveIntensity,
264
+ urgency: Math.min( 1, Math.max( 0, urgency ) ),
265
+ source: this.name,
266
+ } satisfies DriveSignal,
267
+ })
268
+
269
+ // ── Modulation signals ────────────────────────────────
270
+ // Don't modulate during forced rest — the system is unconscious
271
+ if( isForcedRest === 0 && newEnergy <= this._lowThreshold ){
272
+ const degradationFactor = Math.max(
273
+ 0.3,
274
+ 1 - ( ( this._lowThreshold - newEnergy ) / this._lowThreshold ) * 0.7
275
+ )
276
+
277
+ events.push({
278
+ type: 'modulation.cognitive_degradation',
279
+ source: this.name,
280
+ payload: {
281
+ target: '*',
282
+ parameter: 'energy_degradation',
283
+ factor: degradationFactor,
284
+ source: this.name,
285
+ } satisfies ModulationSignal,
286
+ })
287
+ }
288
+
289
+
290
+ // Phase C: publish cognitive event
291
+ const _bus = this._bus
292
+ if( _bus && newEnergy < 20 )
293
+ _bus.publish({ type: 'energy.level.critical', version: 1, sourceEngine: this.name, salience: Math.max( 0.8, this._model.observe( 'energy.critical', 1 - newEnergy / 100 ).salience ), payload: { level: newEnergy } })
294
+ // Phase D + F: rich state-change event — gated by prediction error
295
+ if( _bus ){
296
+ const zoneCode = newEnergy < this._criticalThreshold ? 0 : newEnergy < this._lowThreshold ? 1 : 2
297
+ const predErr = this._model.observe( 'energy.level', newEnergy )
298
+ if( !predErr.gated )
299
+ _bus.publish({ type: 'energy.state.changed', version: 1, sourceEngine: this.name, salience: predErr.salience, payload: { level: newEnergy, zoneCode, stressLoad: state.metrics.get('stress.load') ?? 0, interoceptionComfort: state.metrics.get('interoception.comfort') ?? 0.5 } })
300
+ }
301
+ return { events: events.length > 0 ? events : undefined, commands }
302
+ }
303
+
304
+ // ── Config hot-reload ────────────────────────────────────
305
+
306
+ private _readConfigFromState( state: ReadonlySimulationState ): void {
307
+ const cfg = state.entities.get('engine-config-energy')
308
+ if( !cfg ) return
309
+
310
+ const p = cfg.metadata?.params as Record<string, number> | undefined
311
+ if( !p ) return
312
+
313
+ if( p.baseDecayRate != null ) this._baseDecayRate = p.baseDecayRate
314
+ if( p.restReplenishRate != null ) this._restReplenishRate = p.restReplenishRate
315
+ if( p.lowEnergyThreshold != null ) this._lowThreshold = p.lowEnergyThreshold
316
+ if( p.criticalEnergyThreshold != null ) this._criticalThreshold = p.criticalEnergyThreshold
317
+ if( p.collapseThreshold != null ) this._collapseThreshold = p.collapseThreshold
318
+ if( p.recoveryThreshold != null ) this._recoveryThreshold = p.recoveryThreshold
319
+ }
320
+ }