@mindot/will 0.8.0 → 0.10.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 (142) hide show
  1. package/README.md +15 -11
  2. package/dist/index.d.ts +188 -141
  3. package/dist/index.js +6985 -3337
  4. package/dist/index.js.map +1 -1
  5. package/dist/surface/channels/discord.d.ts +177 -0
  6. package/dist/surface/channels/discord.js +394 -0
  7. package/dist/surface/channels/discord.js.map +1 -0
  8. package/dist/{channels → surface/channels}/whatsapp.d.ts +2 -2
  9. package/dist/{channels → surface/channels}/whatsapp.js +11 -5
  10. package/dist/surface/channels/whatsapp.js.map +1 -0
  11. package/dist/{cli.js → surface/cli.js} +5382 -1573
  12. package/dist/surface/cli.js.map +1 -0
  13. package/dist/{mcp → surface/mcp}/effectors.d.ts +1 -1
  14. package/dist/{mcp → surface/mcp}/effectors.js +10 -4
  15. package/dist/surface/mcp/effectors.js.map +1 -0
  16. package/dist/{will-cS6k4uiJ.d.ts → will-evj9_vrd.d.ts} +6658 -5078
  17. package/package.json +11 -12
  18. package/src/cognition/agency/consequence.ts +356 -1
  19. package/src/cognition/agency/conversation.aim.ts +292 -0
  20. package/src/cognition/agency/engines/action.selector.ts +142 -5
  21. package/src/cognition/agency/engines/affordance.synthesizer.ts +200 -7
  22. package/src/cognition/agency/engines/deliberation.engine.ts +76 -3
  23. package/src/cognition/agency/engines/motor.schema.executor.ts +509 -32
  24. package/src/cognition/agency/engines/reafference.engine.ts +160 -4
  25. package/src/cognition/agency/execution.primitives.ts +17 -4
  26. package/src/cognition/agency/proactive.communicator.ts +19 -3
  27. package/src/cognition/agency/reconcile.learning.ts +5 -4
  28. package/src/cognition/agency/restart.ts +66 -0
  29. package/src/cognition/agency/schemas/innate.ts +96 -1
  30. package/src/cognition/agency/schemas/repertoire.ts +19 -1
  31. package/src/cognition/agency/selection.scoring.ts +49 -0
  32. package/src/cognition/agency/settlement.ts +203 -0
  33. package/src/cognition/agency/types.ts +73 -1
  34. package/src/cognition/cache/composition.ts +232 -0
  35. package/src/cognition/cache/deliberation.cache.ts +219 -0
  36. package/src/cognition/cache/fingerprint.ts +120 -0
  37. package/src/cognition/cache/types.ts +105 -0
  38. package/src/cognition/config.mirror.entities.ts +108 -1
  39. package/src/cognition/event.schemas.ts +22 -8
  40. package/src/cognition/faculties/affective.blender.ts +21 -4
  41. package/src/cognition/faculties/autobiographical.narrator.ts +5 -10
  42. package/src/cognition/faculties/circadian.oscillator.ts +36 -7
  43. package/src/cognition/faculties/episodic.consolidator.ts +59 -3
  44. package/src/cognition/faculties/executive.engine/action.record.ts +129 -0
  45. package/src/cognition/faculties/executive.engine/commands.ts +189 -14
  46. package/src/cognition/faculties/executive.engine/context.ts +106 -46
  47. package/src/cognition/faculties/executive.engine/deliberate.reasoning.ts +1 -1
  48. package/src/cognition/faculties/executive.engine/engine.ts +714 -136
  49. package/src/cognition/faculties/executive.engine/escalation.buffer.ts +230 -45
  50. package/src/cognition/faculties/executive.engine/facet.supervisor.ts +320 -65
  51. package/src/cognition/faculties/executive.engine/facet.ts +81 -26
  52. package/src/cognition/faculties/executive.engine/gating.ts +14 -14
  53. package/src/cognition/faculties/executive.engine/parser.ts +120 -38
  54. package/src/cognition/faculties/executive.engine/prompt.factory.ts +331 -38
  55. package/src/cognition/faculties/executive.engine/types.ts +84 -12
  56. package/src/cognition/faculties/exteroception.ts +99 -98
  57. package/src/cognition/faculties/goal.manager.ts +144 -16
  58. package/src/cognition/faculties/known.entity.tracker.ts +287 -29
  59. package/src/cognition/faculties/moral.evaluator.ts +8 -3
  60. package/src/cognition/faculties/persona.consolidator.ts +141 -0
  61. package/src/cognition/faculties/planning.engine/engine.ts +4 -4
  62. package/src/cognition/faculties/planning.engine/plan.frontier.ts +1 -1
  63. package/src/cognition/faculties/reputation.tracker.ts +66 -2
  64. package/src/cognition/faculties/self.model.updater.ts +19 -12
  65. package/src/cognition/faculties/semantic.engine/integrator.ts +1 -1
  66. package/src/cognition/faculties/social.perception.ts +47 -3
  67. package/src/cognition/faculties/threat.evaluator.ts +7 -0
  68. package/src/cognition/faculties/working.memory.ts +16 -21
  69. package/src/cognition/identity.entity.ts +205 -0
  70. package/src/cognition/index.ts +7 -0
  71. package/src/cognition/instruction.handler.ts +1 -1
  72. package/src/cognition/memory/vector.adapter.ts +12 -3
  73. package/src/cognition/memory/vector.embedder.ts +45 -4
  74. package/src/cognition/percept.entity.ts +122 -0
  75. package/src/cognition/persona.prior.ts +6 -0
  76. package/src/cognition/sense.boundary.ts +176 -0
  77. package/src/cognition/senses/audition.engine/engine.ts +492 -53
  78. package/src/cognition/senses/base.sense.engine.ts +105 -7
  79. package/src/cognition/senses/index.ts +83 -13
  80. package/src/cognition/senses/provenance.ts +128 -0
  81. package/src/cognition/senses/somatosensation.engine.ts +117 -9
  82. package/src/cognition/social.identity.ts +296 -0
  83. package/src/cognition/utilities/token.tracker.ts +94 -10
  84. package/src/core/orchestrator.ts +51 -0
  85. package/src/index.ts +39 -5
  86. package/src/llm/gate.ts +48 -0
  87. package/src/llm/index.ts +127 -33
  88. package/src/llm/routing.ts +6 -0
  89. package/src/llm/summarizer.ts +1 -1
  90. package/src/llm/wire.contracts.ts +57 -0
  91. package/src/pma/index.ts +68 -54
  92. package/src/stem/assembly.audit.ts +1 -0
  93. package/src/stem/guards/identity.coherence.ts +1 -1
  94. package/src/stem/index.ts +171 -23
  95. package/src/stem/mind.ts +198 -57
  96. package/src/stem/policy/arbiter.ts +10 -0
  97. package/src/stem/profiles/built-in.ts +7 -0
  98. package/src/{profiles → stem/profiles}/companion.ts +1 -1
  99. package/src/{profiles → stem/profiles}/company-brain.ts +1 -1
  100. package/src/{profiles → stem/profiles}/customer-service.ts +1 -1
  101. package/src/{profiles → stem/profiles}/game-npc.ts +1 -1
  102. package/src/{profiles → stem/profiles}/index.ts +1 -1
  103. package/src/{profiles → stem/profiles}/smart-home.ts +1 -1
  104. package/src/stem/tracts/effector/escalation.lifecycle.ts +239 -0
  105. package/src/stem/tracts/effector/policy.enforcement.ts +261 -0
  106. package/src/stem/tracts/effector/types.ts +110 -0
  107. package/src/stem/tracts/effector.controller.ts +112 -401
  108. package/src/stem/tracts/outbox.controller.ts +30 -17
  109. package/src/stem/tracts/outbox.writer.ts +40 -2
  110. package/src/stem/tracts/sensory.controller.ts +6 -6
  111. package/src/stem/tracts/session.logger.ts +6 -1
  112. package/src/stem/tracts/transport/types.ts +20 -1
  113. package/src/stem/tracts/transport.controller.ts +33 -9
  114. package/src/surface/channels/discord.ts +609 -0
  115. package/src/{channels → surface/channels}/roster.ts +1 -1
  116. package/src/surface/channels/types.ts +136 -0
  117. package/src/{channels → surface/channels}/whatsapp.ts +22 -10
  118. package/src/{cli.ts → surface/cli.ts} +14 -9
  119. package/src/{host → surface/host}/boot.ts +3 -3
  120. package/src/{host → surface/host}/utterances.ts +2 -2
  121. package/src/{mcp → surface/mcp}/effectors.ts +19 -6
  122. package/src/{mcp → surface/mcp}/server.ts +19 -5
  123. package/src/{sdk → surface/sdk}/will.ts +194 -33
  124. package/src/{serve → surface/serve}/server.ts +11 -4
  125. package/src/types.ts +24 -3
  126. package/dist/channels/discord.d.ts +0 -69
  127. package/dist/channels/discord.js +0 -193
  128. package/dist/channels/discord.js.map +0 -1
  129. package/dist/channels/whatsapp.js.map +0 -1
  130. package/dist/cli.js.map +0 -1
  131. package/dist/mcp/effectors.js.map +0 -1
  132. package/src/channels/discord.ts +0 -214
  133. package/src/channels/types.ts +0 -46
  134. package/src/cognition/faculties/executive.engine/messages.ts +0 -102
  135. package/src/extensions/livestream.ext.ts +0 -570
  136. package/src/extensions/time.ext.ts +0 -339
  137. package/src/profiles/built-in.ts +0 -7
  138. package/src/runners/coherence.runner.ts +0 -49
  139. package/src/runners/outreach.runner.ts +0 -155
  140. package/src/runners/social.runner.ts +0 -179
  141. package/src/runners/thin-shim.runner.ts +0 -205
  142. /package/dist/{cli.d.ts → surface/cli.d.ts} +0 -0
@@ -35,7 +35,12 @@ import type { CognitiveEventSchema } from '#cognition/schema.registry'
35
35
  import type { Affordance, AffordanceSource, MotorSchema, LearnedSkill, SchemaPrecondition } from '#agency/types'
36
36
  import type { SchemaRepertoire } from '#agency/schemas/repertoire'
37
37
  import { INNATE_SCHEMAS } from '#agency/schemas/innate'
38
+ import { CURIOUS_RESOLVED } from '#faculties/known.entity.tracker'
38
39
  import { collectGoalTargets } from '#agency/selection.scoring'
40
+ import { readEffectiveParams } from '#cognition/persona.prior'
41
+ import { liveConsequences, enactionFootprint, spokenAtByEntity, enactedAtBySchemaTarget, CONSEQUENCE_TTL_TICKS, type ConsequenceDescriptor } from '#agency/consequence'
42
+ import { readAliases, canonicalOf } from '#cognition/social.identity'
43
+ import { liveSettlements, settlementForce, type SettlementDescriptor } from '#agency/settlement'
39
44
 
40
45
  /** Default field width for non-innate affordances when no attention metric exists. */
41
46
  const DEFAULT_ATTENTION_CAP = 5
@@ -59,6 +64,38 @@ export class AffordanceSynthesizer implements CognitiveEngine {
59
64
  private _schemas: MotorSchema[]
60
65
  private _skills: SkillAccessor | null = null
61
66
  private _repertoire: SchemaRepertoire | null = null
67
+
68
+ /**
69
+ * This tick's live consequence descriptors — the acts the mind has performed
70
+ * whose outcome has not yet come back. Refreshed once at the top of react()
71
+ * because `_build` runs per candidate and reading them is a full-entity scan.
72
+ */
73
+ private _inFlight: readonly ConsequenceDescriptor[] = []
74
+ /** Durable "when did I last do this TO them" — the entity-bound peer of
75
+ * `_spokenAt`, collected once per tick for the same reason `_inFlight` is. */
76
+ private _enactedAt: ReadonlyMap<string, number> = new Map()
77
+
78
+ /** Ticks an act stays satiating (engine-config-action-selector.repeatWindowTicks). */
79
+ private _satiationWindow: number = CONSEQUENCE_TTL_TICKS
80
+ /** Verdicts System 2 has already reached and that have not yet aged out.
81
+ * Collected once per tick for the same reason `_inFlight` is — `_build` runs
82
+ * per candidate and this is a full-entity scan. */
83
+ private _settled: SettlementDescriptor[] = []
84
+
85
+ /** Tick of the last thing said to each entity — outlives the descriptor sweep. */
86
+ private _spokenAt: ReadonlyMap<string, number> = new Map()
87
+ private _spokeAnywhereAt: number | undefined = undefined
88
+ /**
89
+ * alias id → anchor id, read once per tick.
90
+ *
91
+ * Every surface below is keyed by WHO an act was aimed at, and the mind meets
92
+ * one person under more than one id: a reply is addressed to the transport id
93
+ * the percept arrived with (`discord:1019…`), a self-initiated message to the
94
+ * anchor the executive resolved (`ke:…`). `readSpokenTurns` resolved that for
95
+ * the PROMPT from the start; nothing resolved it for the WEIGHTS, so having
96
+ * just answered someone did not damp reaching out to them a cycle later.
97
+ */
98
+ private _canon: ( id: string ) => string = id => id
62
99
  private _bus: CognitiveBus | null = null
63
100
  private _defaultCap: number
64
101
  private _lastFieldSize = 0
@@ -112,6 +149,40 @@ export class AffordanceSynthesizer implements CognitiveEngine {
112
149
  const valence = metric( state, 'affect.valence', 0 )
113
150
  const energyLow = metric( state, 'energy.level', 0 ) < 30
114
151
 
152
+ // The mind's own acts still in flight (EXAFFERENCE P5). Read once per tick —
153
+ // `_build` runs for every candidate and this is a full-entity scan. Each
154
+ // candidate whose (schema, target) matches one of these carries a decaying
155
+ // `justEnacted`, so having just done a thing damps doing it again.
156
+ // One scan, then every target-keyed surface below shares its id space. They
157
+ // must agree with each other AND with the lookup at the call site: canonical
158
+ // keys read with a raw target damps nothing, and a raw key read with a
159
+ // canonical target breaks the damping that already worked.
160
+ const aliases = readAliases( state.entities )
161
+ this._canon = ( id: string ) => canonicalOf( aliases, id )
162
+
163
+ this._inFlight = liveConsequences( state.entities, tick, this._canon )
164
+ // Durable per-(schema, target) enaction. Descriptors alone expire at the ECHO
165
+ // window, so without this the back half of the satiation window damped
166
+ // nothing for any act with an object that is not speech.
167
+ this._enactedAt = enactedAtBySchemaTarget( state.entities, this._canon )
168
+ // What the mind has already decided. Read here so a verdict reaches the
169
+ // competition as a force in the field rather than a fact about one intent.
170
+ this._settled = liveSettlements( state.entities, tick, this._canon )
171
+ // How long this mind sits with something it has already done before doing it
172
+ // again — the tenant's, not the container's. Falls back to the echo TTL only
173
+ // when unseeded, so a bare harness behaves as before.
174
+ this._satiationWindow = readEffectiveParams( state, 'engine-config-action-selector').repeatWindowTicks
175
+ ?? CONSEQUENCE_TTL_TICKS
176
+ // Durable "when did I last speak to them". Descriptors alone cannot carry
177
+ // satiation — the executor deletes them at their echo TTL, so any window
178
+ // longer than that was a no-op.
179
+ this._spokenAt = spokenAtByEntity( state.entities, this._canon )
180
+ // When this mind last spoke to ANYONE — the satiation arm that is not about
181
+ // the listener. Computed once per tick rather than per candidate.
182
+ let last = -Infinity
183
+ for( const t of this._spokenAt.values() ) if( t > last ) last = t
184
+ this._spokeAnywhereAt = last > -Infinity ? last : undefined
185
+
115
186
  const set: EntityInput[] = []
116
187
  const del: string[] = []
117
188
 
@@ -161,16 +232,18 @@ export class AffordanceSynthesizer implements CognitiveEngine {
161
232
  const personSchemas = schemas.filter( s => s.binds === 'entity')
162
233
  const objectSchemas = schemas.filter( s => s.binds === 'object')
163
234
 
164
- if( personSchemas.length > 0 || objectSchemas.length > 0 )
165
- for( const [ id, e ] of state.entities ){
235
+ // Not gated on there BEING a target-bound schema: `inspect` is offered from
236
+ // this same loop and belongs to the innate floor, so a mind with no `binds`
237
+ // schemas at all — which is every mind until a host declares one — must still
238
+ // reach it. Gating the loop skipped a room entirely, because the innate floor
239
+ // has no `binds: 'object'` schema for a thing to match.
240
+ for( const [ id, e ] of state.entities ){
166
241
  if( e.type !== 'known-entity') continue
167
242
 
168
243
  const m = e.metadata
169
244
  const kind = str( m?.['kind'] )
170
245
  const applicable = kind === 'sentient' ? personSchemas : kind === 'thing' ? objectSchemas : null
171
246
 
172
- if( !applicable || applicable.length === 0 ) continue
173
-
174
247
  const keid = str( m?.['keid'] ) ?? id
175
248
  const fam = num( m?.['familiarity'], 0 )
176
249
  const val = num( m?.['valence'], 0 )
@@ -178,7 +251,7 @@ export class AffordanceSynthesizer implements CognitiveEngine {
178
251
  const salience = fam * 0.6 + Math.max( 0, val ) * 0.3 + res * 0.1 + ( goalTargets.get( keid ) ?? 0 )
179
252
  const name = str( m?.['name'] ) ?? keid
180
253
 
181
- for( const schema of applicable )
254
+ for( const schema of applicable ?? [] )
182
255
  candidates.push({
183
256
  salience,
184
257
  affordance: this._build( schema, tick, state, valence, energyLow, skills, {
@@ -187,6 +260,38 @@ export class AffordanceSynthesizer implements CognitiveEngine {
187
260
  parameters: { targetEntityName: name },
188
261
  } ),
189
262
  })
263
+
264
+ // ── looking at something I cannot place ──────────────────
265
+ //
266
+ // The wanting and the doing referenced different things. Curiosity is
267
+ // per-REFERENT — `drive.curiosity_resolve` rises with
268
+ // `familiarity × (1 − resolutionConfidence)`, and GoalManager turns it
269
+ // into a real goal that completes when that referent resolves. But the
270
+ // only `inspect` on offer bound to PERCEPTS, so a mind could want to know
271
+ // what a room was, hold a goal about it, and have no act that addressed
272
+ // it. The pull existed with nowhere to go.
273
+ //
274
+ // Offered here at the strength of the not-knowing itself, so the thing it
275
+ // most wants to place is the thing it is most drawn to look at — and the
276
+ // affordance appears BECAUSE something is unresolved rather than standing
277
+ // permanently on offer. A referent it can already place raises no
278
+ // candidate at all: there is nothing to find out.
279
+ //
280
+ // Alongside the percept-bound offering, not instead of it. Examining what
281
+ // is in front of you and looking up what you cannot place are both real,
282
+ // and they are not the same act.
283
+ if( perceptSchema && res < CURIOUS_RESOLVED ){
284
+ const wonder = fam * ( 1 - res )
285
+ if( wonder > 0 )
286
+ candidates.push({
287
+ salience: wonder + ( goalTargets.get( keid ) ?? 0 ),
288
+ affordance: this._build( perceptSchema, tick, state, valence, energyLow, skills, {
289
+ evokedBy: id,
290
+ targetEntityId: keid,
291
+ parameters: { focus: name, targetEntityName: name },
292
+ } ),
293
+ })
294
+ }
190
295
  }
191
296
 
192
297
  // ── ideomotor candidates: the executive's imagined actions, pre-activated ──
@@ -204,13 +309,18 @@ export class AffordanceSynthesizer implements CognitiveEngine {
204
309
 
205
310
  if( !schema ) continue
206
311
 
312
+ // `priority` is the confidence the executive decided with. It sets BOTH the
313
+ // evoke-salience (field admission) and — via willBias — the activation the
314
+ // selector scores, so a decision made at 0.85 pushes harder than one at 0.5.
315
+ const willBias = clamp01( num( m?.['priority'], 0.8 ) )
207
316
  candidates.push({
208
- salience: IDEOMOTOR_BASE_SALIENCE + num( m?.['priority'], 0.8 ),
317
+ salience: IDEOMOTOR_BASE_SALIENCE + willBias,
209
318
  affordance: this._build( schema, tick, state, valence, energyLow, skills, {
210
319
  evokedBy: id,
211
320
  targetEntityId: str( m?.['targetEntityId'] ),
212
321
  parameters: ( m?.['parameters'] as Record<string, unknown> ) ?? {},
213
322
  source: 'ideomotor',
323
+ willBias,
214
324
  } ),
215
325
  })
216
326
  }
@@ -220,7 +330,7 @@ export class AffordanceSynthesizer implements CognitiveEngine {
220
330
  // action its current frontier needs. The PlanningEngine writes one `plan.prior`
221
331
  // per ready frontier step; each enters the field as a HIGH-salience candidate
222
332
  // (the frontier is willed) carrying a `planBias` the scorer weighs and the
223
- // planId/stepId provenance that flows through to action.outcome so the plan
333
+ // planId/stepId link that flows through to action.outcome so the plan
224
334
  // advances when the field actually enacts it. Like ideomotor, it never bypasses
225
335
  // the selector — if a more pressing affordance wins, the plan simply re-projects
226
336
  // next tick. The suggested schema must resolve in the repertoire; if it does not,
@@ -303,6 +413,7 @@ export class AffordanceSynthesizer implements CognitiveEngine {
303
413
  parameters?: Record<string, unknown>
304
414
  source?: AffordanceSource
305
415
  planBias?: number
416
+ willBias?: number
306
417
  planId?: string
307
418
  stepId?: string
308
419
  },
@@ -313,6 +424,13 @@ export class AffordanceSynthesizer implements CognitiveEngine {
313
424
  // Will's affordance field is byte-identical. Present only once a refusal dented it.
314
425
  const availability = this._repertoire?.availabilityOf( schema.id ) ?? 1
315
426
 
427
+ // What the mind has LEARNED about the person this act is aimed at. Only for a
428
+ // targeted act; 0 for everything else, so the field is unchanged for a mind that
429
+ // knows no one. See Affordance.socialPrior.
430
+ const socialPrior = ctx.targetEntityId
431
+ ? socialStanding( state, ctx.targetEntityId )
432
+ : 0
433
+
316
434
  // Learned value if known, else the schema's intrinsic prior mapped to 0..1.
317
435
  const expectedReward = skill?.valueEstimate ?? clamp01( ( ( schema.baseValence ?? 0 ) + 1 ) / 2 )
318
436
  const expectedValence = schema.baseValence ?? valence
@@ -320,6 +438,35 @@ export class AffordanceSynthesizer implements CognitiveEngine {
320
438
  // Low energy makes everything feel costlier.
321
439
  const cost = clamp01( schema.cost * ( energyLow ? 1.5 : 1 ) )
322
440
 
441
+ // This act's own footprint, if it is still in flight toward this same person.
442
+ // Satiation only applies to acts aimed at someone the mind SPEAKS to — the
443
+ // `conversation.sent` half is keyed by person, so it must not damp, say,
444
+ // inspecting them.
445
+ //
446
+ // For an act with NO OBJECT the footprint is the act itself: there is no
447
+ // target to key on, and "I have just done this" is the whole of the fact.
448
+ // The innate floor is entirely objectless, so without this it could not
449
+ // satiate at all and whichever stance won once won harder each tick after.
450
+ const speaks = schema.tags?.includes('communication') ?? false
451
+ // The lookup half. Only the QUESTION "have I just done this to them" is asked
452
+ // in canonical form — the affordance keeps the id it was built with, because
453
+ // that is the id the act will be delivered against.
454
+ const asked = ctx.targetEntityId ? this._canon( ctx.targetEntityId ) : undefined
455
+ const justEnacted = enactionFootprint(
456
+ this._inFlight, schema.id, asked, tick, this._satiationWindow,
457
+ speaks ? this._spokenAt : undefined,
458
+ skill?.lastEnactedTick,
459
+ speaks ? this._spokeAnywhereAt : undefined,
460
+ // Not gated on `speaks`: this is exactly the arm speech does NOT need
461
+ // (it has `spokenAt`) and every other entity-bound act was missing.
462
+ this._enactedAt,
463
+ )
464
+
465
+ // The mirror of satiation: having thought this through holds the choice for
466
+ // a while, and fades. Keyed exactly as `justEnacted` is, so an objectless
467
+ // verdict cannot leak onto an act that has an object.
468
+ const settled = settlementForce( this._settled, schema.id, asked, tick )
469
+
323
470
  const key = ctx.targetEntityId ?? ctx.evokedBy ?? schema.id
324
471
  const source = ctx.source ?? schema.source
325
472
  // A non-default-source candidate (ideomotor) gets a distinct id so it can coexist
@@ -341,7 +488,11 @@ export class AffordanceSynthesizer implements CognitiveEngine {
341
488
  tags: schema.tags ?? [],
342
489
  ...( schema.description ? { description: schema.description } : {} ),
343
490
  ...( availability < 1 ? { availability } : {} ),
491
+ ...( socialPrior !== 0 ? { socialPrior } : {} ),
492
+ ...( justEnacted > 0 ? { justEnacted } : {} ),
493
+ ...( settled > 0 ? { settled } : {} ),
344
494
  planBias: ctx.planBias,
495
+ willBias: ctx.willBias,
345
496
  planId: ctx.planId,
346
497
  stepId: ctx.stepId,
347
498
  tick,
@@ -366,7 +517,18 @@ export class AffordanceSynthesizer implements CognitiveEngine {
366
517
  tags: a.tags,
367
518
  description: a.description,
368
519
  ...( a.availability !== undefined ? { availability: a.availability } : {} ),
520
+ ...( a.socialPrior !== undefined ? { socialPrior: a.socialPrior } : {} ),
521
+ // The act's own footprint. Omitted when 0 so a mind that has done nothing
522
+ // twice writes a byte-identical field — but WRITTEN when it is not, which
523
+ // it never was: this is the state hop between synthesis and the
524
+ // competition, and `justEnacted` did not cross it.
525
+ ...( a.justEnacted !== undefined ? { justEnacted: a.justEnacted } : {} ),
526
+ // The verdict's standing weight — same hop, same rule. A field the
527
+ // synthesizer computes and the entity does not carry is a field the
528
+ // competition never sees, which is how `justEnacted` stayed dormant.
529
+ ...( a.settled !== undefined ? { settled: a.settled } : {} ),
369
530
  planBias: a.planBias,
531
+ willBias: a.willBias,
370
532
  planId: a.planId,
371
533
  stepId: a.stepId,
372
534
  tick: a.tick,
@@ -415,3 +577,34 @@ function str( v: unknown ): string | undefined {
415
577
  function clamp01( n: number ): number {
416
578
  return n < 0 ? 0 : n > 1 ? 1 : n
417
579
  }
580
+
581
+ /**
582
+ * The mind's learned read on one person, −1..1 (0 = unknown or neutral).
583
+ *
584
+ * Every input is something the mind formed from experience, none is a constant:
585
+ * • ReputationTracker's `trustworthiness`, centred on 0.5 and scaled by that
586
+ * model's own `confidence`, so an opinion held on two interactions pushes
587
+ * far less than one held on fifty.
588
+ * • the mind's current affective tone, as a gentle tilt — feeling low makes
589
+ * reaching for anyone a little less attractive, which is a mood, not a verdict
590
+ * on them, so it is weighted small and applies the same way to everybody.
591
+ *
592
+ * This is the path by which "they never answer me" reaches the competition: the
593
+ * ReputationTracker learns it from `interaction.occurred`, which only started firing
594
+ * once inbound conversation reached social cognition (#113).
595
+ */
596
+ function socialStanding( state: ReadonlySimulationState, keid: string ): number {
597
+ let trust = 0
598
+ for( const e of state.entities.values() ){
599
+ if( e.type !== 'reputation') continue
600
+ const m = e.metadata as Record<string, unknown> | undefined
601
+ if( m?.['keid'] !== keid ) continue
602
+ const t = num( m['trustworthiness'], 0.5 )
603
+ const c = clamp01( num( m['confidence'], 0 ) )
604
+ trust = ( t - 0.5 ) * 2 * c
605
+ break
606
+ }
607
+
608
+ const mood = num( state.metrics.get('affect.valence'), 0 ) * 0.25
609
+ return Math.max( -1, Math.min( 1, trust + mood ) )
610
+ }
@@ -31,6 +31,8 @@ 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
33
  import { revokedIntentIds, revocationId } from '#agency/revocation'
34
+ import { settlementEntity, expiredSettlementIds, SETTLEMENT_TTL_TICKS } from '#agency/settlement'
35
+ import { nameOf, isReferentId } from '#cognition/social.identity'
34
36
 
35
37
  // ── Minimal structural view of the executive's facet machinery ───────────────
36
38
  // Kept structural (not an import of the executive engine) so the agency module
@@ -98,7 +100,10 @@ export class DeliberationEngine implements CognitiveEngine {
98
100
  // to let go of it — and the tombstone with it. We never deliberate a
99
101
  // revoked intent.
100
102
  const revoked = revokedIntentIds( state.entities, tick )
101
- const del: string[] = []
103
+ // Aged-out verdicts go with them. Nothing else owns settlements, and a
104
+ // question whose settlement has expired must be genuinely open again — not
105
+ // merely inert-but-present, which would leave the state growing forever.
106
+ const del: string[] = expiredSettlementIds( state.entities, tick )
102
107
 
103
108
  // One deliberation per tick (the serial bottleneck).
104
109
  let target: { id: string; meta: Record<string, unknown> } | null = null
@@ -136,7 +141,15 @@ export class DeliberationEngine implements CognitiveEngine {
136
141
 
137
142
  return {
138
143
  commands: {
139
- set: [ this._commit( id, meta, chosen, candidates, 'facet') ],
144
+ set: [
145
+ this._commit( id, meta, chosen, candidates, 'facet'),
146
+ // The verdict's trace in the field it was called in to resolve.
147
+ // Written ONLY here, on the path where System 2 actually thought —
148
+ // the no-executive path below confirms the substrate's winner without
149
+ // reaching a conclusion, and a mind should not be held to a verdict it
150
+ // never formed.
151
+ this._settle( chosen, candidates, tick ),
152
+ ],
140
153
  ...( del.length > 0 ? { delete: del } : {} ),
141
154
  metrics: [ [ 'agency.deliberation.count', 1 ] ],
142
155
  },
@@ -186,6 +199,25 @@ export class DeliberationEngine implements CognitiveEngine {
186
199
  }
187
200
  }
188
201
 
202
+ /**
203
+ * Record that this contest was weighed and settled.
204
+ *
205
+ * Keyed on what WON, not on the rival set, so a slightly differently-framed
206
+ * contest still meets a verdict the mind has already reached — the rivals ride
207
+ * along as the introspectable reason rather than as a matching key.
208
+ */
209
+ private _settle( chosen: string, candidates: Candidate[], tick: Tick ): EntityInput {
210
+ const cand = candidates.find( c => c.schema === chosen )
211
+ const over = candidates.filter( c => c.schema !== chosen ).map( c => c.schema )
212
+ return settlementEntity({
213
+ schema: chosen,
214
+ targetEntityId: cand?.targetEntityId,
215
+ ...( over.length > 0 ? { over } : {} ),
216
+ tick,
217
+ expiresAt: tick + SETTLEMENT_TTL_TICKS,
218
+ })
219
+ }
220
+
189
221
  /** Write the deliberating intent back as 'selected' with the chosen action. */
190
222
  private _commit(
191
223
  id: string,
@@ -227,7 +259,35 @@ export class DeliberationEngine implements CognitiveEngine {
227
259
  else
228
260
  lines.push('My automatic action-selection was uncertain. Candidate actions:')
229
261
  candidates.forEach( ( c, i ) => {
230
- const to = c.targetEntityId ? ` toward ${ c.targetEntityId }` : ''
262
+ // What the target IS, never the id it is filed under.
263
+ //
264
+ // This printed `c.targetEntityId` raw, so a mind deliberating was offered
265
+ // "inspect toward agency-intent-30" and "inspect toward
266
+ // affordance-1-orient-orient" — engine bookkeeping ids, and by the time a
267
+ // facet reasons off-tick the affordance entities are already swept. Live,
268
+ // she said so herself: "the content of all three is opaque — I don't know
269
+ // what agency-intent-30 actually is", and chose at 0.3 confidence anyway
270
+ // because the instructions forbid inventing an action outside the list.
271
+ //
272
+ // The prompt factory already holds this line for "## People I Know"
273
+ // ("never leak the raw keid"); the deliberation focus is the one place that
274
+ // did not. Resolved through the same dossier lookup, so a `reach-out toward
275
+ // ke:1sqlkux` now reads as the person's name.
276
+ //
277
+ // Unresolvable ⇒ the clause is DROPPED rather than filled with an id. An
278
+ // option the mind cannot identify should look like what it is — a bare act
279
+ // — instead of borrowing authority from a number it cannot read.
280
+ const to = ( () => {
281
+ const id = c.targetEntityId
282
+ if( !id ) return ''
283
+ const named = nameOf( state.entities as never, id )
284
+ if( named ) return ` toward ${ named }`
285
+ // Unnamed: show it only if it means something to the MIND. A host-supplied
286
+ // target ("ada") does; an opaque anchor or a piece of engine bookkeeping
287
+ // does not, and printing those is what produced "inspect toward
288
+ // agency-intent-30" as a thing to choose.
289
+ return opaqueToTheMind( id ) ? '' : ` toward ${ id }`
290
+ } )()
231
291
  // The ability's meaning, so the facet weighs what each option IS FOR rather
232
292
  // than choosing among bare labels ("give" vs "attack" is a real difference).
233
293
  const what = c.description ? ` — ${ c.description }` : ''
@@ -258,3 +318,16 @@ function extractChosen( decision: unknown, candidates: Candidate[] ): string | u
258
318
  function str( v: unknown ): string | undefined {
259
319
  return typeof v === 'string' ? v : undefined
260
320
  }
321
+
322
+ /**
323
+ * Ids the mind cannot read anything off.
324
+ *
325
+ * A `ke:` anchor is opaque BY DESIGN — 0.9.0 made identity deliberately
326
+ * meaningless as a string — and the rest are the engine's own bookkeeping
327
+ * entities, which exist for one tick and say nothing about the world. Neither
328
+ * belongs in a choice a mind has to make; a host-supplied target does.
329
+ */
330
+ function opaqueToTheMind( id: string ): boolean {
331
+ return isReferentId( id )
332
+ || /^(affordance|agency-intent|agency-outcome|ideomotor|facet|percept)[-:]/.test( id )
333
+ }