@mindot/will 0.5.0 → 0.7.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 (136) hide show
  1. package/dist/channels/discord.d.ts +1 -1
  2. package/dist/channels/discord.js.map +1 -1
  3. package/dist/channels/whatsapp.d.ts +1 -1
  4. package/dist/channels/whatsapp.js.map +1 -1
  5. package/dist/cli.js +998 -59
  6. package/dist/cli.js.map +1 -1
  7. package/dist/index.d.ts +2 -2
  8. package/dist/index.js +998 -59
  9. package/dist/index.js.map +1 -1
  10. package/dist/mcp/effectors.d.ts +1 -1
  11. package/dist/mcp/effectors.js.map +1 -1
  12. package/dist/{will-BDq-TMQr.d.ts → will-DAW0l-lY.d.ts} +90 -10
  13. package/package.json +1 -1
  14. package/src/channels/discord.ts +11 -11
  15. package/src/channels/roster.ts +1 -1
  16. package/src/channels/types.ts +1 -1
  17. package/src/channels/whatsapp.ts +25 -25
  18. package/src/cli.ts +20 -20
  19. package/src/cognition/acp.ts +28 -0
  20. package/src/cognition/agency/consequence.ts +174 -0
  21. package/src/cognition/agency/engines/action.selector.ts +333 -48
  22. package/src/cognition/agency/engines/affordance.synthesizer.ts +35 -16
  23. package/src/cognition/agency/engines/deliberation.engine.ts +28 -14
  24. package/src/cognition/agency/engines/motor.schema.executor.ts +90 -14
  25. package/src/cognition/agency/engines/reafference.engine.ts +152 -23
  26. package/src/cognition/agency/execution.primitives.ts +13 -13
  27. package/src/cognition/agency/proactive.communicator.ts +1 -1
  28. package/src/cognition/agency/reconcile.learning.ts +10 -1
  29. package/src/cognition/agency/revocation.ts +79 -0
  30. package/src/cognition/agency/schemas/repertoire.ts +109 -9
  31. package/src/cognition/agency/selection.scoring.ts +32 -10
  32. package/src/cognition/agency/types.ts +9 -0
  33. package/src/cognition/bus.ts +2 -2
  34. package/src/cognition/completion.inbox.ts +1 -1
  35. package/src/cognition/config.mirror.entities.ts +5 -5
  36. package/src/cognition/event.log.ts +2 -2
  37. package/src/cognition/event.schemas.ts +67 -67
  38. package/src/cognition/faculties/aesthetic.evaluator.ts +6 -6
  39. package/src/cognition/faculties/affective.blender.ts +36 -4
  40. package/src/cognition/faculties/attachment.evaluator.ts +6 -6
  41. package/src/cognition/faculties/attention.allocator.ts +63 -8
  42. package/src/cognition/faculties/autobiographical.narrator.ts +3 -3
  43. package/src/cognition/faculties/bias.detector.ts +7 -7
  44. package/src/cognition/faculties/circadian.oscillator.ts +3 -3
  45. package/src/cognition/faculties/confidence.calibrator.ts +7 -7
  46. package/src/cognition/faculties/dream.simulator.ts +5 -5
  47. package/src/cognition/faculties/empathy.simulator.ts +7 -7
  48. package/src/cognition/faculties/energy.regulator.ts +4 -4
  49. package/src/cognition/faculties/episodic.consolidator.ts +6 -6
  50. package/src/cognition/faculties/executive.engine/commands.ts +6 -6
  51. package/src/cognition/faculties/executive.engine/context.ts +42 -42
  52. package/src/cognition/faculties/executive.engine/deferred.effects.ts +2 -2
  53. package/src/cognition/faculties/executive.engine/engine.ts +25 -25
  54. package/src/cognition/faculties/executive.engine/facet.supervisor.ts +12 -12
  55. package/src/cognition/faculties/executive.engine/facet.ts +18 -18
  56. package/src/cognition/faculties/executive.engine/gating.ts +2 -2
  57. package/src/cognition/faculties/executive.engine/messages.ts +3 -3
  58. package/src/cognition/faculties/executive.engine/parser.ts +11 -11
  59. package/src/cognition/faculties/executive.engine/prompt.factory.ts +55 -55
  60. package/src/cognition/faculties/exteroception.ts +99 -5
  61. package/src/cognition/faculties/forgetting.curve.ts +3 -3
  62. package/src/cognition/faculties/frustration.evaluator.ts +6 -6
  63. package/src/cognition/faculties/goal.manager.ts +15 -15
  64. package/src/cognition/faculties/inhibition.controller.ts +3 -3
  65. package/src/cognition/faculties/interoception.ts +3 -3
  66. package/src/cognition/faculties/introspection.engine.ts +3 -3
  67. package/src/cognition/faculties/known.entity.tracker.ts +15 -15
  68. package/src/cognition/faculties/loss.evaluator.ts +2 -2
  69. package/src/cognition/faculties/moral.evaluator.ts +4 -4
  70. package/src/cognition/faculties/novelty.detector.ts +4 -4
  71. package/src/cognition/faculties/persona.consolidator.ts +12 -12
  72. package/src/cognition/faculties/planning.engine/engine.ts +47 -47
  73. package/src/cognition/faculties/planning.engine/plan.frontier.ts +5 -5
  74. package/src/cognition/faculties/planning.engine/plan.store.ts +1 -1
  75. package/src/cognition/faculties/planning.engine/plan.supervision.ts +20 -20
  76. package/src/cognition/faculties/reputation.tracker.ts +6 -6
  77. package/src/cognition/faculties/reward.evaluator.ts +4 -4
  78. package/src/cognition/faculties/self.model.updater.ts +8 -8
  79. package/src/cognition/faculties/semantic.engine/integrator.ts +15 -15
  80. package/src/cognition/faculties/sleep.pressure.regulator.ts +4 -4
  81. package/src/cognition/faculties/social.perception.ts +3 -3
  82. package/src/cognition/faculties/spaced.repetition.ts +2 -2
  83. package/src/cognition/faculties/stress.regulator.ts +27 -4
  84. package/src/cognition/faculties/task.switcher.ts +11 -6
  85. package/src/cognition/faculties/theory.of.mind.ts +6 -6
  86. package/src/cognition/faculties/threat.evaluator.ts +3 -3
  87. package/src/cognition/faculties/working.memory.ts +8 -8
  88. package/src/cognition/generative.model.ts +2 -2
  89. package/src/cognition/memory/vector.adapter.ts +5 -5
  90. package/src/cognition/memory/vector.content.ts +4 -4
  91. package/src/cognition/memory/vector.embedder.ts +9 -9
  92. package/src/cognition/persona.prior.ts +1 -1
  93. package/src/cognition/schema.registry.ts +2 -2
  94. package/src/cognition/senses/audition.engine/engine.ts +2 -2
  95. package/src/cognition/senses/base.sense.engine.ts +1 -1
  96. package/src/cognition/utilities/token.tracker.ts +5 -5
  97. package/src/core/abstracts.ts +1 -1
  98. package/src/core/completion.recorder.ts +2 -2
  99. package/src/core/serialization.ts +3 -3
  100. package/src/core/snapshot.manager.ts +1 -1
  101. package/src/core/state.manager.ts +1 -1
  102. package/src/core/utils.ts +1 -1
  103. package/src/host/boot.ts +30 -30
  104. package/src/host/utterances.ts +1 -1
  105. package/src/llm/index.ts +9 -9
  106. package/src/llm/summarizer.ts +4 -4
  107. package/src/llm/wire.contracts.ts +1 -1
  108. package/src/mcp/effectors.ts +10 -10
  109. package/src/mcp/server.ts +11 -11
  110. package/src/pma/eval.ts +1 -1
  111. package/src/pma/index.ts +21 -21
  112. package/src/runners/outreach.runner.ts +3 -3
  113. package/src/runners/social.runner.ts +1 -1
  114. package/src/runners/thin-shim.runner.ts +1 -1
  115. package/src/sdk/will.ts +5 -5
  116. package/src/serve/server.ts +12 -12
  117. package/src/stem/assembly.audit.ts +3 -3
  118. package/src/stem/guards/identity.coherence.ts +10 -10
  119. package/src/stem/guards/identity.guard.ts +22 -22
  120. package/src/stem/index.ts +26 -11
  121. package/src/stem/mind.ts +12 -12
  122. package/src/stem/policy/arbiter.ts +136 -0
  123. package/src/stem/policy/rule.table.ts +172 -0
  124. package/src/stem/policy/verdict.recorder.ts +0 -0
  125. package/src/stem/tracts/biography.writer.ts +3 -3
  126. package/src/stem/tracts/effector.controller.ts +383 -4
  127. package/src/stem/tracts/health.reporter.ts +1 -1
  128. package/src/stem/tracts/outbox.controller.ts +4 -0
  129. package/src/stem/tracts/outbox.writer.ts +4 -4
  130. package/src/stem/tracts/pma.controller.ts +1 -1
  131. package/src/stem/tracts/replay.controller.ts +10 -10
  132. package/src/stem/tracts/sensory.controller.ts +2 -2
  133. package/src/stem/tracts/session.logger.ts +4 -4
  134. package/src/stem/tracts/transport/socketio.transport.ts +7 -7
  135. package/src/stem/tracts/transport/stream.transport.ts +2 -2
  136. package/src/stem/tracts/transport.controller.ts +15 -15
@@ -103,6 +103,9 @@ export class AffordanceSynthesizer implements CognitiveEngine {
103
103
  // means the executor, which ticks later in the SAME tick, sees a whole
104
104
  // repertoire and can expand a restored mid-flight macro. Idempotent.
105
105
  this._repertoire?.restoreComposites( state.entities )
106
+ // Availability entries (P2) rehydrate the same way, so a restored Will keeps
107
+ // its learned suppressions instead of re-probing forbidden abilities.
108
+ this._repertoire?.restoreAvailability( state.entities )
106
109
 
107
110
  const schemas = this._repertoire?.schemas() ?? this._schemas
108
111
  const skills = this._skills?.() ?? this._repertoire?.skills() ?? null
@@ -114,14 +117,12 @@ export class AffordanceSynthesizer implements CognitiveEngine {
114
117
 
115
118
  // Clear the previous tick's field — affordances are transient.
116
119
  for( const [ id, e ] of state.entities )
117
- if( e.type === 'affordance' ) del.push( id )
120
+ if( e.type === 'affordance') del.push( id )
118
121
 
119
122
  // ── 1. innate floor — always emitted, never attention-capped ──
120
- const floor = schemas.filter( s => s.binds === 'none' )
123
+ const floor = schemas.filter( s => s.binds === 'none')
121
124
  for( const schema of floor )
122
- set.push( this._toEntity(
123
- this._build( schema, tick, state, valence, energyLow, skills, {} ),
124
- ) )
125
+ set.push( this._toEntity( this._build( schema, tick, state, valence, energyLow, skills, {} ) ) )
125
126
 
126
127
  // ── 2. perception-bound candidates, attention-budgeted ───────
127
128
  // Goal-relevance counts at the CAP, not only at selection: an affordance whose
@@ -131,14 +132,16 @@ export class AffordanceSynthesizer implements CognitiveEngine {
131
132
  const candidates: Candidate[] = []
132
133
  const goalTargets: Map<string, number> = collectGoalTargets( state )
133
134
 
134
- const perceptSchema = schemas.find( s => s.binds === 'percept' )
135
+ const perceptSchema = schemas.find( s => s.binds === 'percept')
135
136
  if( perceptSchema )
136
137
  for( const [ id, e ] of state.entities ){
137
- if( e.type !== 'percept' ) continue
138
+ if( e.type !== 'percept') continue
139
+
138
140
  const m = e.metadata
139
141
  const salience = num( m?.['salience'], 0 )
140
142
  const summary = str( m?.['summary'] ) ?? str( m?.['category'] ) ?? 'something'
141
143
  const target = str( m?.['entityId'] ) ?? str( m?.['targetEntityId'] )
144
+
142
145
  candidates.push({
143
146
  salience: salience + ( target ? goalTargets.get( target ) ?? 0 : 0 ),
144
147
  affordance: this._build( perceptSchema, tick, state, valence, energyLow, skills, {
@@ -155,21 +158,26 @@ export class AffordanceSynthesizer implements CognitiveEngine {
155
158
  // things — so the Will can direct `give`/`greet` at someone or `use`/`pick-up`
156
159
  // at something in particular. Each (schema × target) enters as a candidate at
157
160
  // the target's salience and competes through the attention cap.
158
- const personSchemas = schemas.filter( s => s.binds === 'entity' )
159
- const objectSchemas = schemas.filter( s => s.binds === 'object' )
161
+ const personSchemas = schemas.filter( s => s.binds === 'entity')
162
+ const objectSchemas = schemas.filter( s => s.binds === 'object')
163
+
160
164
  if( personSchemas.length > 0 || objectSchemas.length > 0 )
161
165
  for( const [ id, e ] of state.entities ){
162
- if( e.type !== 'known-entity' ) continue
166
+ if( e.type !== 'known-entity') continue
167
+
163
168
  const m = e.metadata
164
169
  const kind = str( m?.['kind'] )
165
170
  const applicable = kind === 'sentient' ? personSchemas : kind === 'thing' ? objectSchemas : null
171
+
166
172
  if( !applicable || applicable.length === 0 ) continue
173
+
167
174
  const keid = str( m?.['keid'] ) ?? id
168
175
  const fam = num( m?.['familiarity'], 0 )
169
176
  const val = num( m?.['valence'], 0 )
170
177
  const res = num( m?.['resolutionConfidence'], 0 )
171
178
  const salience = fam * 0.6 + Math.max( 0, val ) * 0.3 + res * 0.1 + ( goalTargets.get( keid ) ?? 0 )
172
179
  const name = str( m?.['name'] ) ?? keid
180
+
173
181
  for( const schema of applicable )
174
182
  candidates.push({
175
183
  salience,
@@ -188,11 +196,14 @@ export class AffordanceSynthesizer implements CognitiveEngine {
188
196
  // it. This is the AffordanceSource.ideomotor leg: executive intention → an
189
197
  // affordance that competes like any other.
190
198
  for( const [ id, e ] of state.entities ){
191
- if( e.type !== 'ideomotor.intent' ) continue
199
+ if( e.type !== 'ideomotor.intent') continue
200
+
192
201
  const m = e.metadata
193
202
  const schemaId = str( m?.['schema'] )
194
203
  const schema = schemaId ? schemas.find( s => s.id === schemaId ) : undefined
204
+
195
205
  if( !schema ) continue
206
+
196
207
  candidates.push({
197
208
  salience: IDEOMOTOR_BASE_SALIENCE + num( m?.['priority'], 0.8 ),
198
209
  affordance: this._build( schema, tick, state, valence, energyLow, skills, {
@@ -215,11 +226,14 @@ export class AffordanceSynthesizer implements CognitiveEngine {
215
226
  // next tick. The suggested schema must resolve in the repertoire; if it does not,
216
227
  // the prior cannot surface as an action and the plan waits / replans.
217
228
  for( const [ id, e ] of state.entities ){
218
- if( e.type !== 'plan.prior' ) continue
229
+ if( e.type !== 'plan.prior') continue
230
+
219
231
  const m = e.metadata
220
232
  const schemaId = str( m?.['schema'] )
221
233
  const schema = schemaId ? schemas.find( s => s.id === schemaId ) : undefined
234
+
222
235
  if( !schema ) continue
236
+
223
237
  const planBias = clamp01( num( m?.['planBias'], 0.6 ) )
224
238
  candidates.push({
225
239
  salience: IDEOMOTOR_BASE_SALIENCE + planBias,
@@ -266,7 +280,7 @@ export class AffordanceSynthesizer implements CognitiveEngine {
266
280
  })
267
281
  }
268
282
  catch( err ){
269
- logger.warn( `[affordance] bus publish failed: ${ err instanceof Error ? err.message : String( err ) }` )
283
+ logger.warn(`[affordance] bus publish failed: ${ err instanceof Error ? err.message : String( err ) }`)
270
284
  }
271
285
  }
272
286
 
@@ -295,9 +309,12 @@ export class AffordanceSynthesizer implements CognitiveEngine {
295
309
  ): Affordance {
296
310
  const skill = skills?.get( schema.id )
297
311
 
312
+ // Policy availability (P2): omitted when fully available (1), so a never-refused
313
+ // Will's affordance field is byte-identical. Present only once a refusal dented it.
314
+ const availability = this._repertoire?.availabilityOf( schema.id ) ?? 1
315
+
298
316
  // Learned value if known, else the schema's intrinsic prior mapped to 0..1.
299
- const expectedReward = skill?.valueEstimate
300
- ?? clamp01( ( ( schema.baseValence ?? 0 ) + 1 ) / 2 )
317
+ const expectedReward = skill?.valueEstimate ?? clamp01( ( ( schema.baseValence ?? 0 ) + 1 ) / 2 )
301
318
  const expectedValence = schema.baseValence ?? valence
302
319
  const habitStrength = skill?.habitStrength ?? 0
303
320
  // Low energy makes everything feel costlier.
@@ -323,6 +340,7 @@ export class AffordanceSynthesizer implements CognitiveEngine {
323
340
  available: this._available( schema.preconditions, ( k ) => metric( state, k, 0 ) ),
324
341
  tags: schema.tags ?? [],
325
342
  ...( schema.description ? { description: schema.description } : {} ),
343
+ ...( availability < 1 ? { availability } : {} ),
326
344
  planBias: ctx.planBias,
327
345
  planId: ctx.planId,
328
346
  stepId: ctx.stepId,
@@ -347,6 +365,7 @@ export class AffordanceSynthesizer implements CognitiveEngine {
347
365
  available: a.available,
348
366
  tags: a.tags,
349
367
  description: a.description,
368
+ ...( a.availability !== undefined ? { availability: a.availability } : {} ),
350
369
  planBias: a.planBias,
351
370
  planId: a.planId,
352
371
  stepId: a.stepId,
@@ -374,7 +393,7 @@ export class AffordanceSynthesizer implements CognitiveEngine {
374
393
  }
375
394
 
376
395
  private _attentionCap( state: ReadonlySimulationState ): number {
377
- const cap = state.metrics.get( 'attention.capacity' ) ?? this._defaultCap
396
+ const cap = state.metrics.get('attention.capacity') ?? this._defaultCap
378
397
  return Math.max( 1, Math.min( MAX_ATTENTION_CAP, Math.round( cap ) ) )
379
398
  }
380
399
  }
@@ -30,6 +30,7 @@ import type {
30
30
  import type { CognitiveBus } from '#cognition/bus'
31
31
  import type { CognitiveEngine, EngineResult } from '#cognition/types'
32
32
  import type { CognitiveEventSchema } from '#cognition/schema.registry'
33
+ import { revokedIntentIds, revocationId } from '#agency/revocation'
33
34
 
34
35
  // ── Minimal structural view of the executive's facet machinery ───────────────
35
36
  // Kept structural (not an import of the executive engine) so the agency module
@@ -42,7 +43,7 @@ interface DeliberationFacetHandle {
42
43
  destroy(): void
43
44
  }
44
45
  export interface DeliberationFacetProvider {
45
- spawnFacet( role?: 'deliberation' ): { attention: 'available' | 'full'; handle?: DeliberationFacetHandle }
46
+ spawnFacet( role?: 'deliberation'): { attention: 'available' | 'full'; handle?: DeliberationFacetHandle }
46
47
  }
47
48
 
48
49
  interface Candidate {
@@ -92,15 +93,23 @@ export class DeliberationEngine implements CognitiveEngine {
92
93
  state: ReadonlySimulationState,
93
94
  _context: SimulationContext,
94
95
  ): Promise<EngineResult> {
96
+ // Honor commitment revocations first (EXAFFERENCE P4): a `deliberating`
97
+ // intent under a live tombstone is dropped — the world ruptured hard enough
98
+ // to let go of it — and the tombstone with it. We never deliberate a
99
+ // revoked intent.
100
+ const revoked = revokedIntentIds( state.entities, tick )
101
+ const del: string[] = []
102
+
95
103
  // One deliberation per tick (the serial bottleneck).
96
104
  let target: { id: string; meta: Record<string, unknown> } | null = null
97
105
  for( const [ id, e ] of state.entities ){
98
- if( e.type !== 'agency.intent' ) continue
99
- if( str( e.metadata?.['status'] ) !== 'deliberating' ) continue
106
+ if( e.type !== 'agency.intent') continue
107
+ if( str( e.metadata?.['status'] ) !== 'deliberating') continue
108
+ if( revoked.has( id ) ){ del.push( id, revocationId( id ) ); continue } // revoked → drop
100
109
  const meta = ( e.metadata ?? {} ) as Record<string, unknown>
101
110
  if( !target || id < target.id ) target = { id, meta } // stable pick
102
111
  }
103
- if( !target ) return { commands: {} }
112
+ if( !target ) return del.length > 0 ? { commands: { delete: del } } : { commands: {} }
104
113
 
105
114
  const { id, meta } = target
106
115
  const provisional = str( meta['schema'] ) ?? 'wait'
@@ -108,7 +117,8 @@ export class DeliberationEngine implements CognitiveEngine {
108
117
 
109
118
  // No executive → confirm the substrate's winner (graceful System-1).
110
119
  if( !this._provider )
111
- return { commands: { set: [ this._commit( id, meta, provisional, candidates, 'no-executive' ) ] } }
120
+ return { commands: { set: [ this._commit( id, meta, provisional, candidates, 'no-executive') ],
121
+ ...( del.length > 0 ? { delete: del } : {} ) } }
112
122
 
113
123
  // Deliberate through a UNIFIED facet (same persona/context as the master).
114
124
  const chosen = await this._deliberate( state, candidates, provisional, meta )
@@ -126,7 +136,8 @@ export class DeliberationEngine implements CognitiveEngine {
126
136
 
127
137
  return {
128
138
  commands: {
129
- set: [ this._commit( id, meta, chosen, candidates, 'facet' ) ],
139
+ set: [ this._commit( id, meta, chosen, candidates, 'facet') ],
140
+ ...( del.length > 0 ? { delete: del } : {} ),
130
141
  metrics: [ [ 'agency.deliberation.count', 1 ] ],
131
142
  },
132
143
  }
@@ -145,7 +156,7 @@ export class DeliberationEngine implements CognitiveEngine {
145
156
  if( !this._handle ){
146
157
  const spawned = this._provider!.spawnFacet('deliberation')
147
158
  if( spawned.attention === 'full' || !spawned.handle ){
148
- logger.info( '[deliberation] facet budget full — confirming substrate winner' )
159
+ logger.info('[deliberation] facet budget full — confirming substrate winner')
149
160
  return provisional
150
161
  }
151
162
  this._handle = spawned.handle
@@ -170,7 +181,7 @@ export class DeliberationEngine implements CognitiveEngine {
170
181
  // Director/state not ready (e.g. executive hasn't run yet) or LLM failure →
171
182
  // fall back to the substrate winner. Drop a possibly-dead handle.
172
183
  this._handle = null
173
- logger.warn( `[deliberation] facet unavailable, confirming winner: ${ err instanceof Error ? err.message : String( err ) }` )
184
+ logger.warn(`[deliberation] facet unavailable, confirming winner: ${ err instanceof Error ? err.message : String( err ) }`)
174
185
  return provisional
175
186
  }
176
187
  }
@@ -208,10 +219,13 @@ export class DeliberationEngine implements CognitiveEngine {
208
219
  // Channel B: if this choice arose by interrupting a pending action, name it so the
209
220
  // facet owns the interruption in-character rather than reasoning in a vacuum.
210
221
  const preemptedFrom = str( meta['preemptedFrom'] )
211
- if( preemptedFrom )
212
- lines.push( `I just broke off a pending action ("${ preemptedFrom }") because something more pressing pulled at me. Decide what to do now:` )
222
+ const revokedBy = str( meta['revokedBy'] )
223
+ if( revokedBy )
224
+ lines.push(`Something in my situation just shifted and I let go of what I was weighing ("${ revokedBy }"). Decide afresh what to do now:`)
225
+ else if( preemptedFrom )
226
+ lines.push(`I just broke off a pending action ("${ preemptedFrom }") because something more pressing pulled at me. Decide what to do now:`)
213
227
  else
214
- lines.push( 'My automatic action-selection was uncertain. Candidate actions:' )
228
+ lines.push('My automatic action-selection was uncertain. Candidate actions:')
215
229
  candidates.forEach( ( c, i ) => {
216
230
  const to = c.targetEntityId ? ` toward ${ c.targetEntityId }` : ''
217
231
  // The ability's meaning, so the facet weighs what each option IS FOR rather
@@ -220,9 +234,9 @@ export class DeliberationEngine implements CognitiveEngine {
220
234
  // Channel B: name the plan link so the facet chooses as the self pursuing it,
221
235
  // not blindly among labels ("this one is the next step of the plan I'm on").
222
236
  const plan = c.fromPlan ? " (my current plan's next step)" : ''
223
- lines.push( `${ i + 1 }. ${ c.schema }${ to }${ what }${ plan }` )
237
+ lines.push(`${ i + 1 }. ${ c.schema }${ to }${ what }${ plan }`)
224
238
  })
225
- return lines.join( '\n' )
239
+ return lines.join('\n')
226
240
  }
227
241
  }
228
242
 
@@ -230,7 +244,7 @@ export class DeliberationEngine implements CognitiveEngine {
230
244
 
231
245
  /** Pull the chosen schema from a facet decision, validated against the candidates. */
232
246
  function extractChosen( decision: unknown, candidates: Candidate[] ): string | undefined {
233
- if( !decision || typeof decision !== 'object' ) return undefined
247
+ if( !decision || typeof decision !== 'object') return undefined
234
248
  const actions = ( decision as Record<string, unknown> )['actions']
235
249
  if( !Array.isArray( actions ) ) return undefined
236
250
  const valid = new Set( candidates.map( c => c.schema ) )
@@ -38,9 +38,16 @@ import type { AccessGrants } from '#agency/access.grants'
38
38
  import type { ActionRequest, ActionResult } from '#types'
39
39
  import { INNATE_SCHEMAS } from '#agency/schemas/innate'
40
40
  import { enact, type Enaction } from '#agency/execution.primitives'
41
+ import { revokedIntentIds, revocationId, staleRevocationIds } from '#agency/revocation'
42
+ import {
43
+ CONSEQUENCE_TYPE, CONSEQUENCE_TTL_TICKS,
44
+ consequenceEntity, fnv1a, paramsKey,
45
+ } from '#agency/consequence'
41
46
 
42
- /** Ticks an async (communicate/external) intent may stay 'awaiting' before it is abandoned. */
43
- const AWAIT_TIMEOUT = 15
47
+ /** Ticks an async (communicate/external) intent may stay 'awaiting' before it is
48
+ * abandoned. Exported: the ReafferenceEngine's sensory-confirmation path (P5)
49
+ * stands down at this boundary so the executor's timeout-failure wins. */
50
+ export const AWAIT_TIMEOUT = 15
44
51
 
45
52
  /** Map a communicate schema to the ProactiveCommunicator effector + the permission name. */
46
53
  const COMM_SCHEMA_TO_EFFECTOR: Record<string, string> = {
@@ -134,15 +141,48 @@ export class MotorSchemaExecutor implements CognitiveEngine {
134
141
  const del: string[] = []
135
142
  const metrics: Array<[ string, number ]> = []
136
143
 
137
- const energy = state.metrics.get( 'energy.level' ) ?? 100
138
- const stress = state.metrics.get( 'stress.load' ) ?? 0
144
+ const energy = state.metrics.get('energy.level') ?? 100
145
+ const stress = state.metrics.get('stress.load' ) ?? 0
146
+
147
+ // ── Expire consequence descriptors (EXAFFERENCE P1) ──────────
148
+ // Descriptors deliberately outlive intent resolution (the sensory echo of a
149
+ // reconciled action still arrives); their only cleanup is this TTL sweep.
150
+ for( const [ id, e ] of state.entities ){
151
+ if( e.type !== CONSEQUENCE_TYPE ) continue
152
+ if( tick >= num( e.metadata?.['expiresAt'], 0 ) ) del.push( id )
153
+ }
154
+
155
+ // ── Revocation tombstones (EXAFFERENCE P4) ───────────────────
156
+ // Reap expired tombstones (intent vanished otherwise), and collect live ones
157
+ // so the selected-processing loop can refuse the half-race case: Deliberation
158
+ // committed `selected` the same tick the tombstone was written (both read the
159
+ // pre-tombstone snapshot), so the intent surfaces here still needing to die.
160
+ del.push( ...staleRevocationIds( state.entities, tick ) )
161
+ const revoked = revokedIntentIds( state.entities, tick )
162
+
163
+ // A tombstoned intent dies whatever its status — including an 'expanding'
164
+ // composite parent preempted mid-routine (registry #4) — and takes its
165
+ // sub-intents with it, in any state ('selected' queued by the executor's
166
+ // own in-tick advance, or 'awaiting' a host). The selected-loop guard below
167
+ // additionally prevents enacting any of them this tick.
168
+ if( revoked.size > 0 )
169
+ for( const [ id, e ] of state.entities ){
170
+ if( e.type !== 'agency.intent') continue
171
+ const parentId = str( e.metadata?.['parentIntentId'] )
172
+ if( revoked.has( id ) ) del.push( id, revocationId( id ) )
173
+ else if( parentId && revoked.has( parentId ) ) del.push( id )
174
+ }
139
175
 
140
176
  // ── Timeout stranded async intents ───────────────────────────
141
177
  // An 'awaiting' intent whose host/delivery never returned would block the
142
178
  // serial Will forever. After AWAIT_TIMEOUT ticks, abandon it as a failed
143
179
  // outcome (which also teaches reafference the action is unreliable here).
144
180
  for( const [ id, e ] of state.entities ){
145
- if( e.type !== 'agency.intent' || str( e.metadata?.['status'] ) !== 'awaiting' ) continue
181
+ if( e.type !== 'agency.intent' || str( e.metadata?.['status'] ) !== 'awaiting') continue
182
+ // POLICY_REAFFERENCE P4 — an escalated intent is HELD: the stem owns its
183
+ // lifecycle (extended TTL → approve/deny/expire), so the executor must not
184
+ // time it out at AWAIT_TIMEOUT and reconcile it as a phantom failure.
185
+ if( e.metadata?.['escalated'] === true ) continue
146
186
  const dispatchedAt = num( e.metadata?.['dispatchedAt'], tick )
147
187
  if( tick - dispatchedAt < AWAIT_TIMEOUT ) continue
148
188
 
@@ -160,17 +200,22 @@ export class MotorSchemaExecutor implements CognitiveEngine {
160
200
  this._emitEnacted( intent, timedOut, predicted, tick )
161
201
  if( intent.planId && intent.planStepId )
162
202
  this._emitActionOutcome( intent, false, 0, 1, tick )
163
- logger.info( `[motor] ⏱ "${ intent.schema }" timed out after ${ tick - dispatchedAt } ticks` )
203
+ logger.info(`[motor] ⏱ "${ intent.schema }" timed out after ${ tick - dispatchedAt } ticks`)
164
204
  }
165
205
 
166
206
  // Process committed intents in a stable order (determinism / replay).
167
207
  const selected = [ ...state.entities.entries() ]
168
- .filter( ( [ , e ] ) => e.type === 'agency.intent' && str( e.metadata?.['status'] ) === 'selected' )
208
+ .filter( ( [ , e ] ) => e.type === 'agency.intent' && str( e.metadata?.['status'] ) === 'selected')
169
209
  .sort( ( a, b ) => ( a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : 0 ) )
170
210
 
171
211
  let enactedCount = 0
172
212
 
173
213
  for( const [ id, e ] of selected ){
214
+ // Revoked mid-commit (P4), or a sub of a preempted composite (#4) — refuse
215
+ // to enact; the sweep above already queued the deletes.
216
+ if( revoked.has( id ) ) continue
217
+ const parentOf = str( e.metadata?.['parentIntentId'] )
218
+ if( parentOf && revoked.has( parentOf ) ) continue
174
219
  const intent = readIntent( id, e.metadata )
175
220
  const schema = this._resolve( intent.schema )
176
221
 
@@ -190,7 +235,7 @@ export class MotorSchemaExecutor implements CognitiveEngine {
190
235
  : { mode: 'external', success: true, outcomeQuality: 0.5, valence: 0,
191
236
  description: `Unknown schema "${ intent.schema }" routed to the host.` }
192
237
 
193
- if( enaction.mode === 'sync' ){
238
+ if( enaction.mode === 'sync'){
194
239
  set.push( outcomeEntity( tick, intent, enaction, predicted ) )
195
240
  del.push( id )
196
241
  if( enaction.metricDeltas ) metrics.push( ...enaction.metricDeltas )
@@ -224,6 +269,26 @@ export class MotorSchemaExecutor implements CognitiveEngine {
224
269
  predictedValence: predicted.expectedValence,
225
270
  },
226
271
  })
272
+ // EXAFFERENCE P1 — the dispatched action's expected sensory footprint,
273
+ // so the world's answer can be recognized as ours when it arrives
274
+ // through the senses (P2). Host acks correlate by intent id already.
275
+ // For a communicate whose words are authored, also carry the text so an
276
+ // echo of them can be matched (P2) and, if the intent is still awaiting,
277
+ // confirm it through the senses (P5) instead of timing out as a failure.
278
+ const awaitingText = enaction.mode === 'communicate'
279
+ ? ( str( intent.parameters['content'] ) ?? firstMessage( intent.parameters['messages'] ) )
280
+ : undefined
281
+ set.push( consequenceEntity({
282
+ intentId: id, schema: intent.schema,
283
+ mode: enaction.mode === 'communicate' ? 'communicate' : 'external',
284
+ ...( enaction.mode === 'communicate'
285
+ ? { effector: COMM_SCHEMA_TO_EFFECTOR[ intent.schema ] ?? intent.schema }
286
+ : {} ),
287
+ ...( intent.targetEntityId ? { targetEntityId: intent.targetEntityId } : {} ),
288
+ ...( awaitingText ? { text: awaitingText, textHash: fnv1a( awaitingText ) } : {} ),
289
+ paramsHash: fnv1a( paramsKey( intent.parameters ) ),
290
+ expiresAt: tick + CONSEQUENCE_TTL_TICKS, tick,
291
+ }) )
227
292
  this._emitDispatch( intent, enaction.mode, tick )
228
293
  metrics.push([ enaction.mode === 'communicate'
229
294
  ? 'agency.communicate.dispatched'
@@ -253,7 +318,7 @@ export class MotorSchemaExecutor implements CognitiveEngine {
253
318
  metadata: { ...meta, status: 'expanding', steps, cursor: 0, accumQuality: 0, accumValence: 0, completed: 0 },
254
319
  })
255
320
  set.push( this._subIntent( parentId, intent.targetEntityId, intent.parameters, steps[0]!, 0, tick ) )
256
- logger.info( `[motor] composite "${ intent.schema }" → ${ steps.length } steps` )
321
+ logger.info(`[motor] composite "${ intent.schema }" → ${ steps.length } steps`)
257
322
  }
258
323
 
259
324
  private _advance(
@@ -380,7 +445,7 @@ export class MotorSchemaExecutor implements CognitiveEngine {
380
445
  if( bubbles.length === 0 && this._author ){
381
446
  const name = str( intent.parameters['targetEntityName'] ) ?? intent.targetEntityId ?? 'them'
382
447
  try { bubbles = await this._author.authorOutreach( intent.targetEntityId ?? '', name, str( intent.parameters['gist'] ) ) }
383
- catch( err ){ logger.warn( `[motor] outreach authoring failed: ${ errMsg( err ) }` ) }
448
+ catch( err ){ logger.warn(`[motor] outreach authoring failed: ${ errMsg( err ) }`) }
384
449
  }
385
450
  if( bubbles.length === 0 ) return false // nothing authored to send → await
386
451
 
@@ -394,13 +459,24 @@ export class MotorSchemaExecutor implements CognitiveEngine {
394
459
  }
395
460
  let result: ActionResult
396
461
  try { result = await this._comms.executeAction( request, state ) }
397
- catch( err ){ logger.warn( `[motor] communicate delivery failed: ${ errMsg( err ) }` ); return false }
462
+ catch( err ){ logger.warn(`[motor] communicate delivery failed: ${ errMsg( err ) }`); return false }
398
463
 
399
464
  if( result.commands.set?.length ) set.push( ...result.commands.set )
400
465
  const out: Enaction = { mode: 'communicate', success: result.success,
401
466
  outcomeQuality: result.feedback.outcomeQuality, valence: 0, description: result.description }
402
467
  set.push( outcomeEntity( tick, intent, out, predicted ) )
403
468
  del.push( id )
469
+ // EXAFFERENCE P1 — the delivered words' sensory footprint: the channel echo
470
+ // or a quote-back of this exact text should read as ours, not as the world
471
+ // surprising us (P2 matches on the content hash).
472
+ if( result.success )
473
+ set.push( consequenceEntity({
474
+ intentId: id, schema: intent.schema, mode: 'communicate', effector,
475
+ ...( intent.targetEntityId ? { targetEntityId: intent.targetEntityId } : {} ),
476
+ textHash: fnv1a( bubbles.join('\n') ),
477
+ text: bubbles.join('\n'),
478
+ expiresAt: tick + CONSEQUENCE_TTL_TICKS, tick,
479
+ }) )
404
480
  this._emitEnacted( intent, out, predicted, tick )
405
481
  this._emitActionOutcome( intent, result.success, result.feedback.outcomeQuality,
406
482
  clamp01( Math.abs( predicted.expectedReward - result.feedback.outcomeQuality ) ), tick )
@@ -420,7 +496,7 @@ export class MotorSchemaExecutor implements CognitiveEngine {
420
496
  payload: { schema: intent.schema, success: enaction.success, outcomeQuality: enaction.outcomeQuality, surprise, tick },
421
497
  })
422
498
  }
423
- catch( err ){ logger.warn( `[motor] enacted publish failed: ${ errMsg( err ) }` ) }
499
+ catch( err ){ logger.warn(`[motor] enacted publish failed: ${ errMsg( err ) }`) }
424
500
  }
425
501
 
426
502
  /**
@@ -452,7 +528,7 @@ export class MotorSchemaExecutor implements CognitiveEngine {
452
528
  },
453
529
  })
454
530
  }
455
- catch( err ){ logger.warn( `[motor] action outcome publish failed: ${ errMsg( err ) }` ) }
531
+ catch( err ){ logger.warn(`[motor] action outcome publish failed: ${ errMsg( err ) }`) }
456
532
  }
457
533
 
458
534
  private _emitDispatch( intent: Intent, mode: 'communicate' | 'external', tick: Tick ): void {
@@ -469,7 +545,7 @@ export class MotorSchemaExecutor implements CognitiveEngine {
469
545
  },
470
546
  })
471
547
  }
472
- catch( err ){ logger.warn( `[motor] dispatch publish failed: ${ errMsg( err ) }` ) }
548
+ catch( err ){ logger.warn(`[motor] dispatch publish failed: ${ errMsg( err ) }`) }
473
549
  }
474
550
  }
475
551