@mindot/will 0.4.0 → 0.6.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 (135) hide show
  1. package/README.md +32 -12
  2. package/dist/channels/discord.d.ts +2 -11
  3. package/dist/channels/discord.js.map +1 -1
  4. package/dist/channels/whatsapp.d.ts +72 -0
  5. package/dist/channels/whatsapp.js +252 -0
  6. package/dist/channels/whatsapp.js.map +1 -0
  7. package/dist/cli.js +837 -91
  8. package/dist/cli.js.map +1 -1
  9. package/dist/index.d.ts +2 -2
  10. package/dist/index.js +620 -79
  11. package/dist/index.js.map +1 -1
  12. package/dist/mcp/effectors.d.ts +1 -1
  13. package/dist/mcp/effectors.js.map +1 -1
  14. package/dist/types-E9-HV-SW.d.ts +11 -0
  15. package/dist/{will-D-slky1N.d.ts → will-Bikuk4s2.d.ts} +56 -12
  16. package/package.json +12 -3
  17. package/src/channels/discord.ts +11 -11
  18. package/src/channels/roster.ts +1 -1
  19. package/src/channels/types.ts +1 -1
  20. package/src/channels/whatsapp.ts +318 -0
  21. package/src/cli.ts +46 -23
  22. package/src/cognition/acp.ts +28 -0
  23. package/src/cognition/agency/consequence.ts +174 -0
  24. package/src/cognition/agency/engines/action.selector.ts +301 -48
  25. package/src/cognition/agency/engines/affordance.synthesizer.ts +26 -16
  26. package/src/cognition/agency/engines/deliberation.engine.ts +28 -14
  27. package/src/cognition/agency/engines/motor.schema.executor.ts +86 -14
  28. package/src/cognition/agency/engines/reafference.engine.ts +122 -18
  29. package/src/cognition/agency/execution.primitives.ts +13 -13
  30. package/src/cognition/agency/proactive.communicator.ts +1 -1
  31. package/src/cognition/agency/reconcile.learning.ts +1 -1
  32. package/src/cognition/agency/revocation.ts +79 -0
  33. package/src/cognition/agency/schemas/repertoire.ts +2 -2
  34. package/src/cognition/agency/selection.scoring.ts +25 -9
  35. package/src/cognition/bus.ts +2 -2
  36. package/src/cognition/completion.inbox.ts +1 -1
  37. package/src/cognition/config.mirror.entities.ts +5 -5
  38. package/src/cognition/event.log.ts +2 -2
  39. package/src/cognition/event.schemas.ts +67 -67
  40. package/src/cognition/faculties/aesthetic.evaluator.ts +6 -6
  41. package/src/cognition/faculties/affective.blender.ts +36 -4
  42. package/src/cognition/faculties/attachment.evaluator.ts +6 -6
  43. package/src/cognition/faculties/attention.allocator.ts +63 -8
  44. package/src/cognition/faculties/autobiographical.narrator.ts +3 -3
  45. package/src/cognition/faculties/bias.detector.ts +7 -7
  46. package/src/cognition/faculties/circadian.oscillator.ts +3 -3
  47. package/src/cognition/faculties/confidence.calibrator.ts +7 -7
  48. package/src/cognition/faculties/dream.simulator.ts +5 -5
  49. package/src/cognition/faculties/empathy.simulator.ts +7 -7
  50. package/src/cognition/faculties/energy.regulator.ts +4 -4
  51. package/src/cognition/faculties/episodic.consolidator.ts +6 -6
  52. package/src/cognition/faculties/executive.engine/commands.ts +6 -6
  53. package/src/cognition/faculties/executive.engine/context.ts +42 -42
  54. package/src/cognition/faculties/executive.engine/deferred.effects.ts +2 -2
  55. package/src/cognition/faculties/executive.engine/engine.ts +27 -26
  56. package/src/cognition/faculties/executive.engine/facet.supervisor.ts +12 -12
  57. package/src/cognition/faculties/executive.engine/facet.ts +18 -18
  58. package/src/cognition/faculties/executive.engine/gating.ts +2 -2
  59. package/src/cognition/faculties/executive.engine/messages.ts +3 -3
  60. package/src/cognition/faculties/executive.engine/parser.ts +11 -11
  61. package/src/cognition/faculties/executive.engine/prompt.factory.ts +55 -55
  62. package/src/cognition/faculties/exteroception.ts +99 -5
  63. package/src/cognition/faculties/forgetting.curve.ts +3 -3
  64. package/src/cognition/faculties/frustration.evaluator.ts +6 -6
  65. package/src/cognition/faculties/goal.manager.ts +15 -15
  66. package/src/cognition/faculties/inhibition.controller.ts +3 -3
  67. package/src/cognition/faculties/interoception.ts +3 -3
  68. package/src/cognition/faculties/introspection.engine.ts +3 -3
  69. package/src/cognition/faculties/known.entity.tracker.ts +15 -15
  70. package/src/cognition/faculties/loss.evaluator.ts +2 -2
  71. package/src/cognition/faculties/moral.evaluator.ts +4 -4
  72. package/src/cognition/faculties/novelty.detector.ts +4 -4
  73. package/src/cognition/faculties/persona.consolidator.ts +12 -12
  74. package/src/cognition/faculties/planning.engine/engine.ts +47 -47
  75. package/src/cognition/faculties/planning.engine/plan.frontier.ts +5 -5
  76. package/src/cognition/faculties/planning.engine/plan.store.ts +1 -1
  77. package/src/cognition/faculties/planning.engine/plan.supervision.ts +20 -20
  78. package/src/cognition/faculties/reputation.tracker.ts +6 -6
  79. package/src/cognition/faculties/reward.evaluator.ts +4 -4
  80. package/src/cognition/faculties/self.model.updater.ts +8 -8
  81. package/src/cognition/faculties/semantic.engine/integrator.ts +15 -15
  82. package/src/cognition/faculties/sleep.pressure.regulator.ts +4 -4
  83. package/src/cognition/faculties/social.perception.ts +3 -3
  84. package/src/cognition/faculties/spaced.repetition.ts +2 -2
  85. package/src/cognition/faculties/stress.regulator.ts +27 -4
  86. package/src/cognition/faculties/task.switcher.ts +11 -6
  87. package/src/cognition/faculties/theory.of.mind.ts +6 -6
  88. package/src/cognition/faculties/threat.evaluator.ts +3 -3
  89. package/src/cognition/faculties/working.memory.ts +8 -8
  90. package/src/cognition/generative.model.ts +2 -2
  91. package/src/cognition/memory/vector.adapter.ts +5 -5
  92. package/src/cognition/memory/vector.content.ts +4 -4
  93. package/src/cognition/memory/vector.embedder.ts +9 -9
  94. package/src/cognition/persona.prior.ts +1 -1
  95. package/src/cognition/schema.registry.ts +2 -2
  96. package/src/cognition/senses/audition.engine/engine.ts +2 -2
  97. package/src/cognition/senses/base.sense.engine.ts +1 -1
  98. package/src/cognition/utilities/token.tracker.ts +11 -5
  99. package/src/core/abstracts.ts +1 -1
  100. package/src/core/completion.recorder.ts +2 -2
  101. package/src/core/serialization.ts +3 -3
  102. package/src/core/snapshot.manager.ts +1 -1
  103. package/src/core/state.manager.ts +1 -1
  104. package/src/core/utils.ts +1 -1
  105. package/src/host/boot.ts +59 -37
  106. package/src/host/utterances.ts +1 -1
  107. package/src/llm/index.ts +84 -34
  108. package/src/llm/summarizer.ts +4 -4
  109. package/src/llm/wire.contracts.ts +1 -1
  110. package/src/mcp/effectors.ts +10 -10
  111. package/src/mcp/server.ts +11 -11
  112. package/src/pma/eval.ts +1 -1
  113. package/src/pma/index.ts +21 -21
  114. package/src/runners/outreach.runner.ts +3 -3
  115. package/src/runners/social.runner.ts +1 -1
  116. package/src/runners/thin-shim.runner.ts +1 -1
  117. package/src/sdk/will.ts +20 -11
  118. package/src/serve/server.ts +12 -12
  119. package/src/stem/assembly.audit.ts +3 -3
  120. package/src/stem/guards/identity.coherence.ts +13 -12
  121. package/src/stem/guards/identity.guard.ts +22 -22
  122. package/src/stem/index.ts +11 -11
  123. package/src/stem/mind.ts +12 -12
  124. package/src/stem/tracts/biography.writer.ts +3 -3
  125. package/src/stem/tracts/effector.controller.ts +4 -4
  126. package/src/stem/tracts/health.reporter.ts +1 -1
  127. package/src/stem/tracts/outbox.controller.ts +4 -0
  128. package/src/stem/tracts/outbox.writer.ts +4 -4
  129. package/src/stem/tracts/pma.controller.ts +1 -1
  130. package/src/stem/tracts/replay.controller.ts +10 -10
  131. package/src/stem/tracts/sensory.controller.ts +2 -2
  132. package/src/stem/tracts/session.logger.ts +4 -4
  133. package/src/stem/tracts/transport/socketio.transport.ts +7 -7
  134. package/src/stem/tracts/transport/stream.transport.ts +2 -2
  135. package/src/stem/tracts/transport.controller.ts +15 -15
package/src/sdk/will.ts CHANGED
@@ -171,12 +171,14 @@ export interface CreateWillOptions {
171
171
  * Unset fields fall back to WILL_LLM_* envs. apiKey stays in memory only.
172
172
  * (Named llmConfig because `llm` is the mock/anthropic MODE switch.) */
173
173
  llmConfig?: WillLLMConfig
174
- /**
175
- * LLM mode. 'mock' (default when no ANTHROPIC_API_KEY) runs a deterministic
176
- * canned executive — zero keys, zero cost. 'anthropic' calls the real model
177
- * (needs ANTHROPIC_API_KEY / WILL_LLM_* env). Omit to auto-detect.
174
+ /**
175
+ * LLM mode. 'mock' (default when no key is present) runs a deterministic
176
+ * canned executive — zero keys, zero cost. 'anthropic' calls Claude (needs
177
+ * ANTHROPIC_API_KEY / WILL_LLM_* env); 'glm' calls Z.ai's GLM over its
178
+ * Anthropic-compatible endpoint (needs ZAI_API_KEY / WILL_LLM_*). Omit to
179
+ * auto-detect from whichever key is set.
178
180
  */
179
- llm?: 'mock' | 'anthropic'
181
+ llm?: 'mock' | 'anthropic' | 'glm'
180
182
  /**
181
183
  * Abilities the Will can choose to enact. `name → handler`, or
182
184
  * `name → { handler, description?, cost?, valence?, preconditions? }` to seed
@@ -360,7 +362,7 @@ export class Will {
360
362
 
361
363
  /** Split an effectors-map entry into a handler + an EffectorDeclaration. */
362
364
  private _register( name: string, entry: EffectorEntry ): void {
363
- if( typeof entry === 'function' ){
365
+ if( typeof entry === 'function'){
364
366
  this._effectors.set( name, entry )
365
367
  this._effectorDecls.set( name, name ) // bare name — uniform prior
366
368
  return
@@ -393,8 +395,8 @@ export class Will {
393
395
  return {
394
396
  tick: s.tick,
395
397
  metrics: {
396
- energy: m( 'energy.level', 100 ), stress: m( 'stress.load' ), sleep: m( 'sleep.pressure' ),
397
- valence: m( 'affect.valence' ), arousal: m( 'affect.arousal' ),
398
+ energy: m('energy.level', 100 ), stress: m('stress.load'), sleep: m('sleep.pressure'),
399
+ valence: m('affect.valence'), arousal: m('affect.arousal'),
398
400
  },
399
401
  goals: c.goalManager.getActiveGoals().map( g => ( { description: g.description, priority: g.priority } ) ),
400
402
  beliefs: c.semanticIntegrator.getBeliefs().map( b => ( { statement: b.statement, confidence: b.confidence } ) ),
@@ -459,7 +461,14 @@ export class Will {
459
461
  // ── Internals ──────────────────────────────────────────────
460
462
 
461
463
  private _buildConfig( id: string, opts: CreateWillOptions ): WillConfig {
462
- const useMock = ( opts.llm ?? ( process.env.ANTHROPIC_API_KEY ? 'anthropic' : 'mock' ) ) === 'mock'
464
+ // Auto-detect from whichever provider key is present; explicit `llm` wins.
465
+ const mode = opts.llm
466
+ ?? ( process.env.ANTHROPIC_API_KEY ? 'anthropic' : process.env.ZAI_API_KEY ? 'glm' : 'mock')
467
+ const useMock = mode === 'mock'
468
+ // `llm: 'glm'` selects the provider; an explicit llmConfig still overrides it.
469
+ const llmConfig = mode === 'glm'
470
+ ? { provider: 'glm' as const, ...opts.llmConfig }
471
+ : opts.llmConfig
463
472
  return {
464
473
  id, name: opts.name,
465
474
  identity: {
@@ -470,7 +479,7 @@ export class Will {
470
479
  },
471
480
  anatomy: opts.anatomy ?? 'mind',
472
481
  model: opts.model,
473
- llm: opts.llmConfig,
482
+ llm: llmConfig,
474
483
  testMode: useMock,
475
484
  persistentMemory: opts.persist ?? false,
476
485
  snapshotInterval: 100,
@@ -572,5 +581,5 @@ export class Will {
572
581
  const COMMUNICATION = [ 'listen', 'talk', 'text' ] as const
573
582
 
574
583
  function slug( s: string ): string {
575
- return s.toLowerCase().replace( /[^a-z0-9]+/g, '-' ).replace( /^-+|-+$/g, '' ) || 'will'
584
+ return s.toLowerCase().replace( /[^a-z0-9]+/g, '-').replace( /^-+|-+$/g, '') || 'will'
576
585
  }
@@ -42,7 +42,7 @@ function json( res: ServerResponse, status: number, body: unknown ): void {
42
42
  async function readJsonBody( req: IncomingMessage ): Promise<Record<string, unknown>> {
43
43
  const chunks: Buffer[] = []
44
44
  for await ( const c of req ) chunks.push( c as Buffer )
45
- const raw = Buffer.concat( chunks ).toString( 'utf8' ).trim()
45
+ const raw = Buffer.concat( chunks ).toString('utf8').trim()
46
46
  if( !raw ) return {}
47
47
  return JSON.parse( raw ) as Record<string, unknown>
48
48
  }
@@ -61,9 +61,9 @@ export function buildWillHttpServer( will: Will, opts: WillHttpOptions = {} ): S
61
61
  const frame = `event: ${ event }\ndata: ${ JSON.stringify( data ) }\n\n`
62
62
  for( const res of streams ) res.write( frame )
63
63
  }
64
- will.on( 'message', m => fanout( 'utterance', m ) )
65
- will.on( 'emotion', a => fanout( 'emotion', a ) )
66
- will.on( 'effector', a => fanout( 'action', a ) )
64
+ will.on('message', m => fanout('utterance', m ) )
65
+ will.on('emotion', a => fanout('emotion', a ) )
66
+ will.on('effector', a => fanout('action', a ) )
67
67
 
68
68
  const server = createServer( ( req, res ) => {
69
69
  void handle( req, res ).catch( err => {
@@ -74,10 +74,10 @@ export function buildWillHttpServer( will: Will, opts: WillHttpOptions = {} ): S
74
74
  } )
75
75
 
76
76
  async function handle( req: IncomingMessage, res: ServerResponse ): Promise<void> {
77
- const url = new URL( req.url ?? '/', 'http://sidecar' )
77
+ const url = new URL( req.url ?? '/', 'http://sidecar')
78
78
  const route = `${ req.method } ${ url.pathname }`
79
79
 
80
- if( req.method === 'OPTIONS' ){
80
+ if( req.method === 'OPTIONS'){
81
81
  res.writeHead( 204, {
82
82
  'access-control-allow-origin': '*',
83
83
  'access-control-allow-methods': 'GET, POST, OPTIONS',
@@ -109,8 +109,8 @@ export function buildWillHttpServer( will: Will, opts: WillHttpOptions = {} ): S
109
109
  }
110
110
 
111
111
  case 'GET /next-utterance': {
112
- const within = Math.min( Math.max( parseInt( url.searchParams.get( 'within_ms' ) ?? '15000' ) || 15_000, 100 ), 120_000 )
113
- const from = url.searchParams.get( 'from' ) ?? undefined
112
+ const within = Math.min( Math.max( parseInt( url.searchParams.get('within_ms') ?? '15000') || 15_000, 100 ), 120_000 )
113
+ const from = url.searchParams.get('from') ?? undefined
114
114
  const msg = await tap.next( within, from )
115
115
  return msg
116
116
  ? json( res, 200, { utterance: msg } )
@@ -124,10 +124,10 @@ export function buildWillHttpServer( will: Will, opts: WillHttpOptions = {} ): S
124
124
  'connection': 'keep-alive',
125
125
  'access-control-allow-origin': '*',
126
126
  } )
127
- res.write( `event: hello\ndata: ${ JSON.stringify( { name: will.name, tick: will.state().tick } ) }\n\n` )
127
+ res.write(`event: hello\ndata: ${ JSON.stringify( { name: will.name, tick: will.state().tick } ) }\n\n`)
128
128
  streams.add( res )
129
- const heartbeat = setInterval( () => res.write( `: tick ${ will.state().tick }\n\n` ), SSE_HEARTBEAT_MS )
130
- req.on( 'close', () => { clearInterval( heartbeat ); streams.delete( res ) } )
129
+ const heartbeat = setInterval( () => res.write(`: tick ${ will.state().tick }\n\n`), SSE_HEARTBEAT_MS )
130
+ req.on('close', () => { clearInterval( heartbeat ); streams.delete( res ) } )
131
131
  return
132
132
  }
133
133
 
@@ -148,7 +148,7 @@ export function buildWillHttpServer( will: Will, opts: WillHttpOptions = {} ): S
148
148
  }
149
149
 
150
150
  // Close open SSE streams when the server closes (so close() can complete).
151
- server.on( 'close', () => { for( const res of streams ) res.end(); streams.clear() } )
151
+ server.on('close', () => { for( const res of streams ) res.end(); streams.clear() } )
152
152
 
153
153
  return server
154
154
  }
@@ -36,7 +36,7 @@ export interface WiringRecord {
36
36
 
37
37
  /** `attachFooBar` → `_fooBar` (the codebase-wide injector/field convention). */
38
38
  function fieldForAttach( method: string ): string {
39
- const stem = method.slice( 'attach'.length )
39
+ const stem = method.slice('attach'.length )
40
40
  return '_' + stem.charAt( 0 ).toLowerCase() + stem.slice( 1 )
41
41
  }
42
42
 
@@ -46,7 +46,7 @@ function attachMethods( engine: object ): string[] {
46
46
  let proto: object | null = engine
47
47
  while( proto && proto !== Object.prototype ){
48
48
  for( const name of Object.getOwnPropertyNames( proto ) )
49
- if( /^attach[A-Z]/.test( name ) && typeof ( engine as Record<string, unknown> )[ name ] === 'function' )
49
+ if( /^attach[A-Z]/.test( name ) && typeof ( engine as Record<string, unknown> )[ name ] === 'function')
50
50
  seen.add( name )
51
51
  proto = Object.getPrototypeOf( proto )
52
52
  }
@@ -84,5 +84,5 @@ export function auditAssemblyWiring( engines: readonly SimulationEngine[] ): Wir
84
84
 
85
85
  /** Compact `engine.attachMethod` keys for the given status (test snapshots). */
86
86
  export function wiringKeys( records: WiringRecord[], status: WiringRecord['status'] ): string[] {
87
- return records.filter( r => r.status === status ).map( r => `${r.engine}.${r.method}` ).sort()
87
+ return records.filter( r => r.status === status ).map( r => `${r.engine}.${r.method}`).sort()
88
88
  }
@@ -18,7 +18,7 @@
18
18
  // ─────────────────────────────────────────────────────────────
19
19
 
20
20
  import type { WillIdentity } from '#stem/mind'
21
- import { LLMDirector, type LLMProvider, type LLMCallMeta } from '#llm/index'
21
+ import { LLMDirector, defaultModelFor, type LLMProvider, type LLMCallMeta } from '#llm/index'
22
22
  import type { TokenTracker } from '#cognition/utilities/token.tracker'
23
23
 
24
24
  export interface CoherenceIssue {
@@ -81,12 +81,12 @@ An empty "issues" array means the persona is fine.`
81
81
  export function buildCoherenceUserMessage( input: CoherenceInput ): string {
82
82
  const id = input.identity
83
83
  const parts = [
84
- `PERSONA PROMPT:\n${( id.prompt ?? '' ).trim() || '(empty)'}`,
85
- `VALUES: ${( id.values ?? [] ).join( ', ' ) || '(none)'}`,
86
- `STYLE: ${( id.style ?? '' ).trim() || '(none)'}`,
84
+ `PERSONA PROMPT:\n${( id.prompt ?? '').trim() || '(empty)'}`,
85
+ `VALUES: ${( id.values ?? [] ).join(', ') || '(none)'}`,
86
+ `STYLE: ${( id.style ?? '').trim() || '(none)'}`,
87
87
  ]
88
- if( input.profileContext ) parts.push( `PROFILE CONTEXT:\n${input.profileContext.trim()}` )
89
- return parts.join( '\n\n' )
88
+ if( input.profileContext ) parts.push(`PROFILE CONTEXT:\n${input.profileContext.trim()}`)
89
+ return parts.join('\n\n')
90
90
  }
91
91
 
92
92
  export async function checkIdentityCoherence(
@@ -104,7 +104,7 @@ export async function checkIdentityCoherence(
104
104
  }
105
105
 
106
106
  const issues = parseIssues( text )
107
- return { ok: !issues.some( i => i.severity === 'error' ), ran: true, issues, raw: text }
107
+ return { ok: !issues.some( i => i.severity === 'error'), ran: true, issues, raw: text }
108
108
  }
109
109
 
110
110
  /** Convenience: build a provider client from env and run the review. */
@@ -112,12 +112,13 @@ export async function reviewIdentityCoherence(
112
112
  input: CoherenceInput,
113
113
  opts: { willId?: string; tokenTracker?: TokenTracker | null } = {},
114
114
  ): Promise<CoherenceResult> {
115
+ const provider = ( process.env.WILL_LLM_PROVIDER ?? 'anthropic') as LLMProvider
115
116
  const director = new LLMDirector({
116
117
  willId: opts.willId ?? 'identity-coherence',
117
- model: process.env.WILL_LLM_MODEL ?? 'claude-sonnet-4-5-20250929',
118
+ model: process.env.WILL_LLM_MODEL ?? defaultModelFor( provider ),
118
119
  maxOutputTokens: 512,
119
120
  apiKey: process.env.WILL_LLM_API_KEY ?? process.env.ANTHROPIC_API_KEY ?? '',
120
- provider: ( process.env.WILL_LLM_PROVIDER ?? 'anthropic' ) as LLMProvider,
121
+ provider,
121
122
  sessionLogger: null,
122
123
  baseUrl: process.env.WILL_LLM_BASE_URL ?? process.env.OPENAI_BASE_URL,
123
124
  // When a per-Will tracker is supplied, the creation-time review records under
@@ -130,8 +131,8 @@ export async function reviewIdentityCoherence(
130
131
  // ── parsing ────────────────────────────────────────────────────
131
132
 
132
133
  function parseIssues( text: string ): CoherenceIssue[] {
133
- const start = text.indexOf( '{' )
134
- const end = text.lastIndexOf( '}' )
134
+ const start = text.indexOf('{')
135
+ const end = text.lastIndexOf('}')
135
136
  if( start < 0 || end <= start ) return []
136
137
 
137
138
  let obj: { issues?: unknown }
@@ -142,7 +143,7 @@ function parseIssues( text: string ): CoherenceIssue[] {
142
143
 
143
144
  const out: CoherenceIssue[] = []
144
145
  for( const raw of obj.issues ){
145
- if( !raw || typeof raw !== 'object' ) continue
146
+ if( !raw || typeof raw !== 'object') continue
146
147
  const r = raw as Record<string, unknown>
147
148
  const detail = typeof r['detail'] === 'string' ? r['detail'] : ''
148
149
  if( !detail ) continue
@@ -110,11 +110,11 @@ const CAPABILITY_CLAIM_PATTERNS: Array<[ RegExp, string ]> = [
110
110
  /** Strip markdown header lines that forge a section the executive prompt owns. */
111
111
  function stripReservedHeaders( text: string ): { text: string; stripped: boolean } {
112
112
  let stripped = false
113
- const out = text.split( '\n' ).filter( line => {
113
+ const out = text.split('\n').filter( line => {
114
114
  const m = /^\s*#{1,6}\s*(.+?)\s*$/.exec( line )
115
115
  if( m && RESERVED_SECTIONS.has( m[1]!.toLowerCase() ) ){ stripped = true; return false }
116
116
  return true
117
- } ).join( '\n' )
117
+ } ).join('\n')
118
118
  return { text: out, stripped }
119
119
  }
120
120
 
@@ -125,59 +125,59 @@ export function validateWillIdentity( input: IdentityGuardInput ): IdentityGuard
125
125
  const id: WillIdentity = input.identity ?? { prompt: '', values: [], traits: {}, style: '' }
126
126
 
127
127
  // ── prompt: hijack strip → length → injection ────────────────
128
- let prompt = ( id.prompt ?? '' ).trim()
128
+ let prompt = ( id.prompt ?? '').trim()
129
129
  const hdr = stripReservedHeaders( prompt )
130
130
  if( hdr.stripped ){
131
131
  prompt = hdr.text.trim()
132
- warnings.push( 'identity.prompt forged reserved section headers (## Personality / ## Output Guidelines / …); stripped to protect prompt structure.' )
132
+ warnings.push('identity.prompt forged reserved section headers (## Personality / ## Output Guidelines / …); stripped to protect prompt structure.')
133
133
  }
134
134
  if( prompt.length > MAX_PROMPT_CHARS )
135
- errors.push( `identity.prompt is ${prompt.length} chars (max ${MAX_PROMPT_CHARS}) — it would dilute the core grounding and inflate cost.` )
135
+ errors.push(`identity.prompt is ${prompt.length} chars (max ${MAX_PROMPT_CHARS}) — it would dilute the core grounding and inflate cost.`)
136
136
  const promptEmpty = prompt.length === 0
137
137
  if( !promptEmpty && prompt.length < MIN_PROMPT_CHARS )
138
- warnings.push( `identity.prompt is very short (${prompt.length} chars) — a thin persona behaves generically.` )
138
+ warnings.push(`identity.prompt is very short (${prompt.length} chars) — a thin persona behaves generically.`)
139
139
  if( INJECTION_PATTERNS.some( re => re.test( prompt ) ) )
140
- warnings.push( 'identity.prompt contains an instruction-injection pattern — it may fight the core grounding; review before deploying.' )
140
+ warnings.push('identity.prompt contains an instruction-injection pattern — it may fight the core grounding; review before deploying.')
141
141
 
142
142
  const claimedSenses = new Set<string>()
143
143
  for( const [ re, sense ] of CAPABILITY_CLAIM_PATTERNS )
144
144
  if( re.test( prompt ) ) claimedSenses.add( sense )
145
145
  if( claimedSenses.size )
146
- warnings.push( `identity.prompt claims capabilities the Will lacks (${[ ...claimedSenses ].join( ', ' )}) — it perceives through text/conversation and may hallucinate using them.` )
146
+ warnings.push(`identity.prompt claims capabilities the Will lacks (${[ ...claimedSenses ].join(', ')}) — it perceives through text/conversation and may hallucinate using them.`)
147
147
 
148
148
  // ── values ───────────────────────────────────────────────────
149
149
  let values = Array.from( new Set( ( id.values ?? [] ).map( v => String( v ).trim() ).filter( Boolean ) ) )
150
150
  if( values.length > MAX_VALUES ){
151
- warnings.push( `identity.values has more than ${MAX_VALUES} entries; truncated.` )
151
+ warnings.push(`identity.values has more than ${MAX_VALUES} entries; truncated.`)
152
152
  values = values.slice( 0, MAX_VALUES )
153
153
  }
154
154
  const valuesEmpty = values.length === 0
155
- if( valuesEmpty ) warnings.push( 'identity.values is empty — values ground the Will’s decisions; consider seeding a few.' )
155
+ if( valuesEmpty ) warnings.push('identity.values is empty — values ground the Will’s decisions; consider seeding a few.')
156
156
 
157
157
  // ── traits: finite → range → vocabulary ──────────────────────
158
158
  const traits: Record<string, number> = {}
159
159
  for( const [ rawKey, rawVal ] of Object.entries( id.traits ?? {} ) ){
160
160
  const key = rawKey.trim()
161
161
  const val = Number( rawVal )
162
- if( !Number.isFinite( val ) ){ errors.push( `trait "${key}" is not a finite number (${String( rawVal )}).` ); continue }
162
+ if( !Number.isFinite( val ) ){ errors.push(`trait "${key}" is not a finite number (${String( rawVal )}).`); continue }
163
163
  let clamped = val
164
164
  if( val < 0 || val > 1 ){
165
165
  clamped = val < 0 ? 0 : 1
166
- warnings.push( `trait "${key}" = ${val} is outside [0,1]; clamped to ${clamped}.` )
166
+ warnings.push(`trait "${key}" = ${val} is outside [0,1]; clamped to ${clamped}.`)
167
167
  }
168
168
  if( !KNOWN_TRAITS.has( key.toLowerCase() ) )
169
- warnings.push( `trait "${key}" is not a recognised trait — it may be ignored by the persona layer.` )
169
+ warnings.push(`trait "${key}" is not a recognised trait — it may be ignored by the persona layer.`)
170
170
  traits[ key ] = clamped
171
171
  }
172
172
 
173
173
  // ── style ─────────────────────────────────────────────────────
174
- let style = ( id.style ?? '' ).trim()
174
+ let style = ( id.style ?? '').trim()
175
175
  if( style.length > MAX_STYLE_CHARS ){
176
- warnings.push( 'identity.style is long; it reads better as a short phrase.' )
176
+ warnings.push('identity.style is long; it reads better as a short phrase.')
177
177
  style = style.slice( 0, MAX_STYLE_CHARS )
178
178
  }
179
179
  if( GENERIC_STYLES.has( style.toLowerCase() ) )
180
- warnings.push( 'identity.style is generic — a distinct voice prevents collapse into a generic chatbot tone.' )
180
+ warnings.push('identity.style is generic — a distinct voice prevents collapse into a generic chatbot tone.')
181
181
 
182
182
  // ── effectors: collisions ─────────────────────────────────────
183
183
  let effectors = input.effectors ?? null
@@ -187,7 +187,7 @@ export function validateWillIdentity( input: IdentityGuardInput ): IdentityGuard
187
187
  for( const a of effectors ){
188
188
  const name = String( a ).trim()
189
189
  if( !name ) continue
190
- if( seen.has( name ) ){ warnings.push( `duplicate effector "${name}" removed.` ); continue }
190
+ if( seen.has( name ) ){ warnings.push(`duplicate effector "${name}" removed.`); continue }
191
191
  seen.add( name )
192
192
  // A custom (non-comms) effector that shadows an innate stance is un-enactable as
193
193
  // a host effector — the innate floor already provides it. Drop it with a warning
@@ -195,7 +195,7 @@ export function validateWillIdentity( input: IdentityGuardInput ): IdentityGuard
195
195
  // list innate stances like `remember`/`reflect`, and the external-schema
196
196
  // synthesizer already skips them (see agency/schemas/external.ts).
197
197
  if( !EXPLICIT_EFFECTORS.has( name ) && INNATE_SCHEMA_BY_ID.has( name ) ){
198
- warnings.push( `effector "${name}" shadows an innate stance — it's provided innately and won't be enacted as a host effector.` )
198
+ warnings.push(`effector "${name}" shadows an innate stance — it's provided innately and won't be enacted as a host effector.`)
199
199
  continue
200
200
  }
201
201
  out.push( name )
@@ -205,12 +205,12 @@ export function validateWillIdentity( input: IdentityGuardInput ): IdentityGuard
205
205
 
206
206
  // ── profile context ──────────────────────────────────────────
207
207
  let profileContext = input.profileContext
208
- if( typeof profileContext === 'string' ){
208
+ if( typeof profileContext === 'string'){
209
209
  const c = stripReservedHeaders( profileContext )
210
- if( c.stripped ) warnings.push( 'profile context forged reserved section headers; stripped.' )
210
+ if( c.stripped ) warnings.push('profile context forged reserved section headers; stripped.')
211
211
  profileContext = c.text.trim()
212
212
  if( profileContext.length > MAX_CONTEXT_CHARS )
213
- errors.push( `profile context is ${profileContext.length} chars (max ${MAX_CONTEXT_CHARS}).` )
213
+ errors.push(`profile context is ${profileContext.length} chars (max ${MAX_CONTEXT_CHARS}).`)
214
214
  }
215
215
 
216
216
  // ── identity strength (collapse signal) ──────────────────────
@@ -222,7 +222,7 @@ export function validateWillIdentity( input: IdentityGuardInput ): IdentityGuard
222
222
  + 0.15 * ( Object.keys( traits ).length > 0 ? 1 : 0 )
223
223
  ) * 100 ) / 100
224
224
  if( identityStrength < 0.4 )
225
- warnings.push( `identity is shallow (strength ${identityStrength}) — the Will behaves generically until it develops one.` )
225
+ warnings.push(`identity is shallow (strength ${identityStrength}) — the Will behaves generically until it develops one.`)
226
226
 
227
227
  return {
228
228
  ok: errors.length === 0,
package/src/stem/index.ts CHANGED
@@ -225,10 +225,10 @@ export class WillStem {
225
225
  const previousState = await simulation.snapshotManager.loadLatestFromStorage()
226
226
  if( previousState ){
227
227
  simulation.stateManager.restore( previousState, { entities: true, metrics: false } )
228
- logger.info( `[WillStem] Restored snapshot for ${config.id} — ${previousState.entities.size} entities loaded` )
228
+ logger.info(`[WillStem] Restored snapshot for ${config.id} — ${previousState.entities.size} entities loaded`)
229
229
  }
230
230
  }
231
- catch( err ){ logger.warn( `[WillStem] Snapshot restore failed for ${config.id} — starting fresh:`, err ) }
231
+ catch( err ){ logger.warn(`[WillStem] Snapshot restore failed for ${config.id} — starting fresh:`, err ) }
232
232
 
233
233
  const
234
234
  dataDir = process.env.WILL_DATA_DIR ?? './data',
@@ -310,7 +310,7 @@ export class WillStem {
310
310
  // Buffer host-owned effector invocations for delivery. The MotorSchemaExecutor
311
311
  // emits `agency.invocation` (intentId = correlation handle) when it holds an
312
312
  // external action 'awaiting'; the host executes it and acks → confirmExecution.
313
- if( event.type === 'agency.invocation' )
313
+ if( event.type === 'agency.invocation')
314
314
  this._effector.bufferInvocation( instance, event.payload as Record<string, unknown> )
315
315
 
316
316
  if( instance.simulationEventListeners.size === 0 ) return
@@ -457,7 +457,7 @@ export class WillStem {
457
457
  instance.simulation.stateManager.applyCommands( flushCmds )
458
458
  const pauseState = instance.simulation.stateManager.snapshot()
459
459
  instance.simulation.snapshotManager.persistNow( pauseState )
460
- .catch( err => logger.error( `[WillStem] snapshot persist failed on pause (${id}):`, err ))
460
+ .catch( err => logger.error(`[WillStem] snapshot persist failed on pause (${id}):`, err ))
461
461
 
462
462
  this._biography.writeSessionSummary( instance )
463
463
  this._biography.writeEmotionalBiographySummary( instance )
@@ -1029,9 +1029,9 @@ export class WillStem {
1029
1029
  // executive confidence, goal outcomes, and significant emotional events.
1030
1030
  if( instance._sessionBehavior ){
1031
1031
  const sb = instance._sessionBehavior
1032
- const v = snapshot.metrics.get( 'affect.valence' ) ?? 0
1033
- const a = snapshot.metrics.get( 'affect.arousal' ) ?? 0
1034
- const c = snapshot.metrics.get( 'executive.confidence' )
1032
+ const v = snapshot.metrics.get('affect.valence') ?? 0
1033
+ const a = snapshot.metrics.get('affect.arousal') ?? 0
1034
+ const c = snapshot.metrics.get('executive.confidence')
1035
1035
 
1036
1036
  // ── Range tracking ──────────────────────────────────────
1037
1037
  if( v < sb.valenceMin ) sb.valenceMin = v
@@ -1039,8 +1039,8 @@ export class WillStem {
1039
1039
  if( a < sb.arousalMin ) sb.arousalMin = a
1040
1040
  if( a > sb.arousalMax ) sb.arousalMax = a
1041
1041
  if( c !== undefined ){ sb.confidenceSum += c; sb.confidenceCount++ }
1042
- const gt = snapshot.metrics.get( 'goals.total' )
1043
- const gc = snapshot.metrics.get( 'goals.completed_total' )
1042
+ const gt = snapshot.metrics.get('goals.total')
1043
+ const gc = snapshot.metrics.get('goals.completed_total')
1044
1044
  if( gt !== undefined ) sb.goalsTotal = gt
1045
1045
  if( gc !== undefined ) sb.goalsCompleted = gc
1046
1046
 
@@ -1101,8 +1101,8 @@ export class WillStem {
1101
1101
  sb.prevArousal = a
1102
1102
 
1103
1103
  // Track impulsive actions: ticks where executive fired with low confidence
1104
- const conf = snapshot.metrics.get( 'executive.confidence' )
1105
- const actCount = Math.round( snapshot.metrics.get( 'executive.action_count' ) ?? 0 )
1104
+ const conf = snapshot.metrics.get('executive.confidence')
1105
+ const actCount = Math.round( snapshot.metrics.get('executive.action_count') ?? 0 )
1106
1106
  if( conf !== undefined && conf < 0.35 && actCount > 0 )
1107
1107
  sb.impulsiveActionCount += actCount
1108
1108
  }
package/src/stem/mind.ts CHANGED
@@ -409,10 +409,10 @@ export function _resolveVectorMemory(
409
409
  const mockMode = process.env.WILL_VECTOR_MEMORY === 'mock'
410
410
  const rawModel = embeddingModel
411
411
  ?? process.env.WILL_EMBEDDING_MODEL
412
- ?? ( process.env.WILL_EMBEDDING_API_KEY ? 'text-embedding-3-small' : 'none' )
412
+ ?? ( process.env.WILL_EMBEDDING_API_KEY ? 'text-embedding-3-small' : 'none')
413
413
 
414
414
  // Explicitly disabled — the documented "none" sentinel or recall turned off.
415
- if( !mockMode && ( rawModel === 'none' || process.env.WILL_SEMANTIC_RECALL === 'false' ) )
415
+ if( !mockMode && ( rawModel === 'none' || process.env.WILL_SEMANTIC_RECALL === 'false') )
416
416
  return { embedder: null, vectorMemory: null }
417
417
 
418
418
  // testMode promises a deterministic, zero-key, offline mind — but a dev .env
@@ -581,9 +581,9 @@ export function assembleMind( willId: string, config: WillConfig ): MindAssembly
581
581
  profileContext: profile?.context,
582
582
  })
583
583
  if( !idGuard.ok )
584
- throw new Error( `Invalid Will identity for "${willId}": ${ idGuard.errors.join( '; ' ) }` )
584
+ throw new Error(`Invalid Will identity for "${willId}": ${ idGuard.errors.join('; ') }`)
585
585
  for( const w of idGuard.warnings )
586
- logger.warn( `[identity-guard] ${willId}: ${w}` )
586
+ logger.warn(`[identity-guard] ${willId}: ${w}`)
587
587
  config = { ...config, identity: idGuard.sanitized.identity }
588
588
 
589
589
  // ── Construct ────────────────────────────────────────────
@@ -602,8 +602,8 @@ export function assembleMind( willId: string, config: WillConfig ): MindAssembly
602
602
  // sessionLogger/grants); tests/unit/assembly.order.test.ts pins that set per
603
603
  // tier, so a NEW unwired attachment fails loudly in CI, not here.
604
604
  for( const rec of auditAssemblyWiring( simulation.orchestrator.engines ) )
605
- if( rec.status === 'unwired' )
606
- logger.debug( `[assembly] ${willId}: ${rec.engine}.${rec.method} unwired at assembly (anatomy=${anatomy})` )
605
+ if( rec.status === 'unwired')
606
+ logger.debug(`[assembly] ${willId}: ${rec.engine}.${rec.method} unwired at assembly (anatomy=${anatomy})`)
607
607
 
608
608
  // ── Seed readable simulation state ───────────────────────
609
609
  // Identity, optional initial goals, and the engine-config mirror.
@@ -772,7 +772,7 @@ function _constructCognition(
772
772
  // ── Planning Engine ──────────────────────────────────────
773
773
  const planningEngine = new PlanningEngine()
774
774
  planningEngine.attachGoalManager( goalManager )
775
- if( anatomy !== 'reflex' ) planningEngine.attachExecutiveEngine( executiveEngine )
775
+ if( anatomy !== 'reflex') planningEngine.attachExecutiveEngine( executiveEngine )
776
776
  executiveEngine.attachPlanningEngine( planningEngine )
777
777
 
778
778
  // ── Executive ────────────────────────────────────────────
@@ -791,7 +791,7 @@ function _constructCognition(
791
791
  autobiographicalNarrator.attachEpisodicConsolidator( episodicConsolidator )
792
792
  autobiographicalNarrator.attachSemanticIntegrator( semanticIntegrator )
793
793
  // Satellites harvest the executive's own output — attach wherever it runs.
794
- if( anatomy !== 'reflex' ){
794
+ if( anatomy !== 'reflex'){
795
795
  autobiographicalNarrator.attachExecutiveEngine( executiveEngine )
796
796
  introspectionEngine.attachExecutiveEngine( executiveEngine )
797
797
  }
@@ -807,7 +807,7 @@ function _constructCognition(
807
807
  empathySimulator.attachTheoryOfMind( theoryOfMind )
808
808
 
809
809
  // ── Context compaction components (mind anatomy only) ──
810
- if( anatomy !== 'reflex' ){
810
+ if( anatomy !== 'reflex'){
811
811
  const summarizer = new ExecutiveSummarizer({
812
812
  summaryInterval: parseInt( process.env.WILL_SUMMARY_INTERVAL ?? '10'),
813
813
  bufferSize: parseInt( process.env.WILL_SUMMARY_BUFFER_SIZE ?? '12'),
@@ -845,7 +845,7 @@ function _constructCognition(
845
845
  const olfactionEngine = new OlfactionEngine()
846
846
  const gustationEngine = new GustationEngine()
847
847
 
848
- if( anatomy !== 'reflex' )
848
+ if( anatomy !== 'reflex')
849
849
  auditionEngine.attachExecutiveEngine( executiveEngine )
850
850
 
851
851
  // §5.4 — cold-spawn digest hydration: on the first turn for an entity, seed an
@@ -906,7 +906,7 @@ function _constructCognition(
906
906
  // winner (graceful System-1 degradation).
907
907
  const deliberationEngine = new DeliberationEngine()
908
908
  deliberationEngine.setWillName( config.name )
909
- if( anatomy !== 'reflex' )
909
+ if( anatomy !== 'reflex')
910
910
  deliberationEngine.attachExecutive( executiveEngine )
911
911
 
912
912
  // ── Build Cognition ──────────────────────────────────────
@@ -1108,7 +1108,7 @@ function _seedIdentity(
1108
1108
  // to infer its identity from context. config.name is the canonical source of truth.
1109
1109
  const nameAlreadyInPrompt = personaText.toLowerCase().includes( config.name.toLowerCase() )
1110
1110
  const namePrefix = nameAlreadyInPrompt ? '' : `I am ${config.name}.`
1111
- const fullPersonaText = [ namePrefix, personaText ].filter( Boolean ).join( ' ' )
1111
+ const fullPersonaText = [ namePrefix, personaText ].filter( Boolean ).join(' ')
1112
1112
 
1113
1113
  const prompt = [
1114
1114
  WILL_CORE_PREAMBLE,
@@ -38,15 +38,15 @@ export class BiographyWriter {
38
38
  if( !fileLoggingEnabled() ) return
39
39
 
40
40
  const dataDir = process.env[ 'WILL_DATA_DIR' ] ?? './data'
41
- const dir = join( dataDir, 'wills', willId, 'profiles' )
41
+ const dir = join( dataDir, 'wills', willId, 'profiles')
42
42
  try {
43
43
  if( !this._ensuredDirs.has( dir ) ){
44
44
  mkdirSync( dir, { recursive: true } )
45
45
  this._ensuredDirs.add( dir )
46
46
  }
47
- appendFileSync( join( dir, file ), JSON.stringify( record ) + '\n', 'utf8' )
47
+ appendFileSync( join( dir, file ), JSON.stringify( record ) + '\n', 'utf8')
48
48
  } catch( err ){
49
- logger.error( `[biography] ${file} write failed:`, err )
49
+ logger.error(`[biography] ${file} write failed:`, err )
50
50
  }
51
51
  }
52
52
  /**
@@ -91,11 +91,11 @@ export class effectorController {
91
91
  const tick = instance.tickCount
92
92
 
93
93
  const intent = instance.simulation.stateManager.snapshot().entities.get( invocationId )
94
- if( !intent || intent.type !== 'agency.intent' ){
94
+ if( !intent || intent.type !== 'agency.intent'){
95
95
  // No awaiting intent for this id. Expected when the executor's 15-tick await
96
96
  // timeout already abandoned it (writing a failed outcome + advancing any plan)
97
97
  // before the host's late ack arrived, or the id is unknown. Drop the straggler.
98
- logger.warn( `[effector] confirmExecution: no awaiting agency.intent "${invocationId}" (timed out / already reconciled?) — ignored` )
98
+ logger.warn(`[effector] confirmExecution: no awaiting agency.intent "${invocationId}" (timed out / already reconciled?) — ignored`)
99
99
  return
100
100
  }
101
101
 
@@ -122,7 +122,7 @@ export class effectorController {
122
122
  if( typeof v === 'number' && Number.isFinite( v ) )
123
123
  instance.simulation.stateManager.setMetric( k, v )
124
124
  else
125
- logger.warn( `[effector] confirmExecution: dropped non-finite metric "${k}"=${String( v )} from host ack (${schema})` )
125
+ logger.warn(`[effector] confirmExecution: dropped non-finite metric "${k}"=${String( v )} from host ack (${schema})`)
126
126
  }
127
127
 
128
128
  instance.sessionLogger?.write({
@@ -135,7 +135,7 @@ export class effectorController {
135
135
  confirmedExternally: true,
136
136
  } as never)
137
137
 
138
- logger.info( `[effector] ✓ reconciled ${result.success ? 'success' : 'failure'}: intent "${invocationId}" (${schema})` )
138
+ logger.info(`[effector] ✓ reconciled ${result.success ? 'success' : 'failure'}: intent "${invocationId}" (${schema})`)
139
139
  }
140
140
  }
141
141
 
@@ -87,7 +87,7 @@ export class HealthReporter {
87
87
  for( const entity of instance.simulation.stateManager.getEntitiesByType('goal') ){
88
88
  totalGoals++
89
89
  const s = entity.metadata?.status
90
- if( s === 'active' || s === 'in_progress' ) activeGoals++
90
+ if( s === 'active' || s === 'in_progress') activeGoals++
91
91
  }
92
92
 
93
93
  const goalScore = totalGoals === 0
@@ -104,6 +104,10 @@ export class OutboxController {
104
104
  : `My message failed to reach the recipient.`,
105
105
  salience: delivered ? 0.35 : 0.6,
106
106
  changeType: delivered ? 'delivered' : 'failed',
107
+ // Reafference by construction — this percept describes our own action's
108
+ // outcome ("ear hears the word"). Tagged, not attenuated: it is the ack
109
+ // surface, not a content echo (EXAFFERENCE P2).
110
+ provenance: 'reafferent',
107
111
  messageId,
108
112
  },
109
113
  })
@@ -53,7 +53,7 @@ export class OutboxWriter {
53
53
  this._sessionLogger = logger
54
54
  }
55
55
 
56
- private _genId( suffix = '' ): string {
56
+ private _genId( suffix = ''): string {
57
57
  return `outbox-${ this._willId }-${ ++this._seq }${ suffix }`
58
58
  }
59
59
 
@@ -61,7 +61,7 @@ export class OutboxWriter {
61
61
  * Push one canonical outbox row and return its generated id. The single point
62
62
  * where the row shape is materialized — all producers funnel through here.
63
63
  */
64
- enqueue( row: OutboxRow, idSuffix = '' ): string {
64
+ enqueue( row: OutboxRow, idSuffix = ''): string {
65
65
  const id = this._genId( idSuffix )
66
66
  this._outbox.push({
67
67
  id,
@@ -105,7 +105,7 @@ export class OutboxWriter {
105
105
 
106
106
  const ids: string[] = []
107
107
  bubbles.forEach( ( bubble, i ) => {
108
- if( !pushToOutbox ){ ids.push( this._genId( `-${ i }` ) ); return }
108
+ if( !pushToOutbox ){ ids.push( this._genId(`-${ i }`) ); return }
109
109
  logger.info(`[outbox-writer] reply → ${ entityId } bubble[${ i }] "${ bubble.slice( 0, 80 ) }"`)
110
110
  ids.push( this.enqueue({
111
111
  targetEntityId: entityId,
@@ -113,7 +113,7 @@ export class OutboxWriter {
113
113
  content: bubble,
114
114
  effectorName: 'text',
115
115
  threadId,
116
- }, `-${ i }` ) )
116
+ }, `-${ i }`) )
117
117
  } )
118
118
 
119
119
  this._sessionLogger?.write({
@@ -29,7 +29,7 @@ export class PMAController {
29
29
  * with existing beliefs may cause unintended merges.
30
30
  */
31
31
  load( id: string, instance: WillInstance, pma: PMASnapshot ): void {
32
- if( instance.status === 'active' )
32
+ if( instance.status === 'active')
33
33
  throw new Error(`Cannot load PMA into an active Will (${id}). Pause first.`)
34
34
 
35
35
  // Re-validate the artifact's persona at the load boundary (Phase 2): a stored