@mindot/will 0.6.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.
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { O as OutboundEnvelope, A as AckResult, a as ExternalTransport, I as InboundEnvelope, T as TransportStatus, S as SimulationContext, b as SeededPRNG, c as SimulationEntity, d as Timestamp, e as SimulationEvent, f as StateManager, g as Tick, h as SimulationState, R as RestoreOptions, i as StateCommands, j as ReasoningFootprint, k as ReadonlySimulationState, C as ConflictReport, l as ConflictStrategy, m as ConflictResolution } from './will-Bikuk4s2.js';
2
- export { n as AckEnvelope, o as ActionRequest, p as ActionResult, q as ActionSelector, r as ActivityEnvelope, s as ActivityEvent, t as ActivityEventHandler, u as AestheticEvaluator, v as AestheticEvaluatorConfig, w as AffectiveBlender, x as AffectiveBlenderConfig, y as AffordanceSynthesizer, z as AsyncEngine, B as AsyncEngineConfig, D as AttachmentEvaluator, F as AttachmentEvaluatorConfig, G as AttentionAllocator, H as AttentionAllocatorConfig, J as AuditionEngine, K as AutobiographicalNarrator, L as AutobiographicalNarratorConfig, M as BehavioralProbeResult, N as BiasDetector, P as BiasDetectorConfig, Q as BunStorageAdapter, U as ChunkEnvelope, V as CircadianConfig, X as CircadianOscillator, Y as ClockConfig, Z as Cognition, _ as CognitiveHealth, $ as ConfidenceCalibrator, a0 as ConfidenceCalibratorConfig, a1 as Coordinates, a2 as CreateWillOptions, a3 as DefaultEventBus, a4 as DefaultMetricCollector, a5 as DefaultOrchestrator, a6 as DefaultReplayRecorder, a7 as DefaultReplaySession, a8 as DefaultScenario, a9 as DefaultSerializer, aa as DefaultSimulation, ab as DefaultSimulationClock, ac as DefaultStateManager, ad as DefaultVectorMemoryAdapter, ae as DeliberationEngine, af as DeltaEncoder, ag as DeltaSnapshot, ah as DreamSimulator, ai as DreamSimulatorConfig, aj as Duration, ak as EffectorDeclaration, al as EffectorEntry, E as EffectorHandler, am as EffectorResult, an as EffectorSpec, ao as EmbeddingProvider, ap as EmpathySimulator, aq as EmpathySimulatorConfig, ar as EnergyRegulator, as as EnergyRegulatorConfig, at as EngineRegistry, au as EngineResult, av as Envelope, aw as EpisodicConsolidator, ax as EpisodicConsolidatorConfig, ay as EventBus, az as EventBusConfig, aA as EventFilter, aB as EventHandler, aC as EventPayload, aD as ExecutiveEngine, aE as ExecutiveEngineConfig, aF as Exteroception, aG as ExteroceptionConfig, aH as ForgettingCurve, aI as ForgettingCurveConfig, aJ as FrustrationEvaluator, aK as FrustrationEvaluatorConfig, aL as GoalManager, aM as GoalManagerConfig, aN as GustationEngine, aO as InboundMessageEnvelope, aP as InboundPerceptEnvelope, aQ as InhibitionController, aR as InhibitionControllerConfig, aS as Interoception, aT as InteroceptionConfig, aU as IntrospectionEngine, aV as IntrospectionEngineConfig, aW as KnownEntityTracker, aX as KnownEntityTrackerConfig, aY as LLMCompletionRecord, aZ as LLMCompletionSink, a_ as LossEvaluator, a$ as LossEvaluatorConfig, b0 as MessageEnvelope, b1 as MetricCollector, b2 as MetricPoint, b3 as MinimalContext, b4 as MockEmbedder, b5 as MoralEvaluator, b6 as MoralEvaluatorConfig, b7 as MotorSchemaExecutor, b8 as NoveltyDetector, b9 as NoveltyDetectorConfig, ba as OlfactionEngine, bb as OpenAICompatibleEmbedder, bc as Orchestrator, bd as OrchestratorConfig, be as OutboxMessage, bf as PMABehavioral, bg as PMABelief, bh as PMAEmotionalBaseline, bi as PMAEvalHarness, bj as PMAGoal, bk as PMAIdentity, bl as PMAProbe, bm as PMASnapshot, bn as PerceptEnvelope, bo as PersonaConsolidator, bp as PersonaConsolidatorConfig, bq as PlanningEngine, br as PlanningEngineConfig, bs as ReafferenceEngine, bt as ReconstructionFidelityReport, bu as ReconstructionFidelityScores, bv as RecordUsageInput, bw as ReplayComparison, bx as ReplayConfig, by as ReplayDifference, bz as ReplayManager, bA as ReplayMetadata, bB as ReplayRecord, bC as ReplayRecorder, bD as ReplaySession, bE as ReplyEnvelope, bF as ReputationTracker, bG as ReputationTrackerConfig, bH as RewardEvaluator, bI as RewardEvaluatorConfig, bJ as Scenario, bK as ScenarioConfig, bL as ScenarioValidationResult, bM as SchemaPrecondition, bN as SelfModelUpdater, bO as SelfModelUpdaterConfig, bP as SemanticIntegrator, bQ as SemanticIntegratorConfig, bR as SensoryInput, bS as SerializationConfig, bT as SerializationFormat, bU as SerializedEntity, bV as SerializedState, bW as Serializer, bX as SessionLogEnvelope, bY as Simulation, bZ as SimulationClock, b_ as SimulationConfig, b$ as SimulationEngine, c0 as SimulationEventBase, c1 as SimulationEventListener, c2 as SleepPressureConfig, c3 as SleepPressureRegulator, c4 as SocialPerception, c5 as SocialPerceptionConfig, c6 as SomatosensationEngine, c7 as SpacedRepetition, c8 as SpacedRepetitionConfig, c9 as StateSnapshot, ca as Stimulus, cb as StorageAdapter, cc as StressRegulator, cd as StressRegulatorConfig, ce as TaskSwitcher, cf as TaskSwitcherConfig, cg as TextMessage, ch as TheoryOfMind, ci as TheoryOfMindConfig, cj as ThreatEvaluator, ck as ThreatEvaluatorConfig, cl as TickListener, cm as TokenLedgerRecord, cn as TokenReportEnvelope, co as TokenTracker, cp as TokenTrackerConfig, cq as TokenUsage, cr as VectorIndex, cs as VectorMemoryAdapter, ct as VectorMemoryConfig, cu as VectorQueryFilter, cv as VectorQueryResult, cw as VectorRecord, cx as VisionEngine, cy as VoiceChunk, W as Will, cz as WillAffect, cA as WillConfig, cB as WillEffectorAct, cC as WillInstance, cD as WillMessage, cE as WillStateSummary, cF as WillStatus, cG as WillStem, cH as WillSummary, cI as WorkingMemory, cJ as WorkingMemoryConfig, cK as WorldEntity, cL as WorldInterface, cM as assembleMind, cN as clearCompletionRecorder, cO as effectorInvocation, cP as effectorInvocationEnvelope, cQ as getCompletionRecorder, cR as resolvePricing, cS as setCompletionRecorder } from './will-Bikuk4s2.js';
1
+ import { O as OutboundEnvelope, A as AckResult, a as ExternalTransport, I as InboundEnvelope, T as TransportStatus, S as SimulationContext, b as SeededPRNG, c as SimulationEntity, d as Timestamp, e as SimulationEvent, f as StateManager, g as Tick, h as SimulationState, R as RestoreOptions, i as StateCommands, j as ReasoningFootprint, k as ReadonlySimulationState, C as ConflictReport, l as ConflictStrategy, m as ConflictResolution } from './will-DAW0l-lY.js';
2
+ export { n as AckEnvelope, o as ActionRequest, p as ActionResult, q as ActionSelector, r as ActivityEnvelope, s as ActivityEvent, t as ActivityEventHandler, u as AestheticEvaluator, v as AestheticEvaluatorConfig, w as AffectiveBlender, x as AffectiveBlenderConfig, y as AffordanceSynthesizer, z as AsyncEngine, B as AsyncEngineConfig, D as AttachmentEvaluator, F as AttachmentEvaluatorConfig, G as AttentionAllocator, H as AttentionAllocatorConfig, J as AuditionEngine, K as AutobiographicalNarrator, L as AutobiographicalNarratorConfig, M as BehavioralProbeResult, N as BiasDetector, P as BiasDetectorConfig, Q as BunStorageAdapter, U as ChunkEnvelope, V as CircadianConfig, X as CircadianOscillator, Y as ClockConfig, Z as Cognition, _ as CognitiveHealth, $ as ConfidenceCalibrator, a0 as ConfidenceCalibratorConfig, a1 as Coordinates, a2 as CreateWillOptions, a3 as DefaultEventBus, a4 as DefaultMetricCollector, a5 as DefaultOrchestrator, a6 as DefaultReplayRecorder, a7 as DefaultReplaySession, a8 as DefaultScenario, a9 as DefaultSerializer, aa as DefaultSimulation, ab as DefaultSimulationClock, ac as DefaultStateManager, ad as DefaultVectorMemoryAdapter, ae as DeliberationEngine, af as DeltaEncoder, ag as DeltaSnapshot, ah as DreamSimulator, ai as DreamSimulatorConfig, aj as Duration, ak as EffectorDeclaration, al as EffectorEntry, E as EffectorHandler, am as EffectorResult, an as EffectorSpec, ao as EmbeddingProvider, ap as EmpathySimulator, aq as EmpathySimulatorConfig, ar as EnergyRegulator, as as EnergyRegulatorConfig, at as EngineRegistry, au as EngineResult, av as Envelope, aw as EpisodicConsolidator, ax as EpisodicConsolidatorConfig, ay as EventBus, az as EventBusConfig, aA as EventFilter, aB as EventHandler, aC as EventPayload, aD as ExecutiveEngine, aE as ExecutiveEngineConfig, aF as Exteroception, aG as ExteroceptionConfig, aH as ForgettingCurve, aI as ForgettingCurveConfig, aJ as FrustrationEvaluator, aK as FrustrationEvaluatorConfig, aL as GoalManager, aM as GoalManagerConfig, aN as GustationEngine, aO as InboundMessageEnvelope, aP as InboundPerceptEnvelope, aQ as InhibitionController, aR as InhibitionControllerConfig, aS as Interoception, aT as InteroceptionConfig, aU as IntrospectionEngine, aV as IntrospectionEngineConfig, aW as KnownEntityTracker, aX as KnownEntityTrackerConfig, aY as LLMCompletionRecord, aZ as LLMCompletionSink, a_ as LossEvaluator, a$ as LossEvaluatorConfig, b0 as MessageEnvelope, b1 as MetricCollector, b2 as MetricPoint, b3 as MinimalContext, b4 as MockEmbedder, b5 as MoralEvaluator, b6 as MoralEvaluatorConfig, b7 as MotorSchemaExecutor, b8 as NoveltyDetector, b9 as NoveltyDetectorConfig, ba as OlfactionEngine, bb as OpenAICompatibleEmbedder, bc as Orchestrator, bd as OrchestratorConfig, be as OutboxMessage, bf as PMABehavioral, bg as PMABelief, bh as PMAEmotionalBaseline, bi as PMAEvalHarness, bj as PMAGoal, bk as PMAIdentity, bl as PMAProbe, bm as PMASnapshot, bn as PerceptEnvelope, bo as PersonaConsolidator, bp as PersonaConsolidatorConfig, bq as PlanningEngine, br as PlanningEngineConfig, bs as ReafferenceEngine, bt as ReconstructionFidelityReport, bu as ReconstructionFidelityScores, bv as RecordUsageInput, bw as ReplayComparison, bx as ReplayConfig, by as ReplayDifference, bz as ReplayManager, bA as ReplayMetadata, bB as ReplayRecord, bC as ReplayRecorder, bD as ReplaySession, bE as ReplyEnvelope, bF as ReputationTracker, bG as ReputationTrackerConfig, bH as RewardEvaluator, bI as RewardEvaluatorConfig, bJ as Scenario, bK as ScenarioConfig, bL as ScenarioValidationResult, bM as SchemaPrecondition, bN as SelfModelUpdater, bO as SelfModelUpdaterConfig, bP as SemanticIntegrator, bQ as SemanticIntegratorConfig, bR as SensoryInput, bS as SerializationConfig, bT as SerializationFormat, bU as SerializedEntity, bV as SerializedState, bW as Serializer, bX as SessionLogEnvelope, bY as Simulation, bZ as SimulationClock, b_ as SimulationConfig, b$ as SimulationEngine, c0 as SimulationEventBase, c1 as SimulationEventListener, c2 as SleepPressureConfig, c3 as SleepPressureRegulator, c4 as SocialPerception, c5 as SocialPerceptionConfig, c6 as SomatosensationEngine, c7 as SpacedRepetition, c8 as SpacedRepetitionConfig, c9 as StateSnapshot, ca as Stimulus, cb as StorageAdapter, cc as StressRegulator, cd as StressRegulatorConfig, ce as TaskSwitcher, cf as TaskSwitcherConfig, cg as TextMessage, ch as TheoryOfMind, ci as TheoryOfMindConfig, cj as ThreatEvaluator, ck as ThreatEvaluatorConfig, cl as TickListener, cm as TokenLedgerRecord, cn as TokenReportEnvelope, co as TokenTracker, cp as TokenTrackerConfig, cq as TokenUsage, cr as VectorIndex, cs as VectorMemoryAdapter, ct as VectorMemoryConfig, cu as VectorQueryFilter, cv as VectorQueryResult, cw as VectorRecord, cx as VisionEngine, cy as VoiceChunk, W as Will, cz as WillAffect, cA as WillConfig, cB as WillEffectorAct, cC as WillInstance, cD as WillMessage, cE as WillStateSummary, cF as WillStatus, cG as WillStem, cH as WillSummary, cI as WorkingMemory, cJ as WorkingMemoryConfig, cK as WorldEntity, cL as WorldInterface, cM as assembleMind, cN as clearCompletionRecorder, cO as effectorInvocation, cP as effectorInvocationEnvelope, cQ as getCompletionRecorder, cR as resolvePricing, cS as setCompletionRecorder } from './will-DAW0l-lY.js';
3
3
 
4
4
  /** Decides how emit() resolves an ack for a given envelope. Default: acked via callback. */
5
5
  type AckPolicy = (env: OutboundEnvelope) => AckResult;
package/dist/index.js CHANGED
@@ -18724,7 +18724,9 @@ function risk(a, bias) {
18724
18724
  return clamp015(Math.max(0, -a.expectedValence) * 0.5 + bias.threat * 0.5);
18725
18725
  }
18726
18726
  function scoreAffordance(a, bias, w = DEFAULT_WEIGHTS) {
18727
- return w.goal * goalRelevance(a, bias) + w.reward * a.expectedReward + w.novelty * novelty(a) + w.drive * driveUrgency(a, bias) + w.habit * a.habitStrength + w.plan * (a.planBias ?? 0) - w.cost * a.cost - w.inhib * bias.inhibition - w.risk * risk(a, bias);
18727
+ const raw = w.goal * goalRelevance(a, bias) + w.reward * a.expectedReward + w.novelty * novelty(a) + w.drive * driveUrgency(a, bias) + w.habit * a.habitStrength + w.plan * (a.planBias ?? 0) - w.cost * a.cost - w.inhib * bias.inhibition - w.risk * risk(a, bias);
18728
+ const availability = a.availability ?? 1;
18729
+ return raw > 0 ? raw * availability : raw;
18728
18730
  }
18729
18731
  function stakes(winner, bias) {
18730
18732
  return clamp015(Math.max(
@@ -18803,6 +18805,7 @@ var AffordanceSynthesizer = class {
18803
18805
  // ── react ─────────────────────────────────────────────────────
18804
18806
  async react(_delta, tick, state, _context) {
18805
18807
  this._repertoire?.restoreComposites(state.entities);
18808
+ this._repertoire?.restoreAvailability(state.entities);
18806
18809
  const schemas = this._repertoire?.schemas() ?? this._schemas;
18807
18810
  const skills = this._skills?.() ?? this._repertoire?.skills() ?? null;
18808
18811
  const valence = metric(state, "affect.valence", 0);
@@ -18928,6 +18931,7 @@ var AffordanceSynthesizer = class {
18928
18931
  /** Compose an Affordance from a schema + the evoking context, folding in learned priors. */
18929
18932
  _build(schema, tick, state, valence, energyLow, skills, ctx) {
18930
18933
  const skill = skills?.get(schema.id);
18934
+ const availability = this._repertoire?.availabilityOf(schema.id) ?? 1;
18931
18935
  const expectedReward = skill?.valueEstimate ?? clamp016(((schema.baseValence ?? 0) + 1) / 2);
18932
18936
  const expectedValence = schema.baseValence ?? valence;
18933
18937
  const habitStrength = skill?.habitStrength ?? 0;
@@ -18949,6 +18953,7 @@ var AffordanceSynthesizer = class {
18949
18953
  available: this._available(schema.preconditions, (k) => metric(state, k, 0)),
18950
18954
  tags: schema.tags ?? [],
18951
18955
  ...schema.description ? { description: schema.description } : {},
18956
+ ...availability < 1 ? { availability } : {},
18952
18957
  planBias: ctx.planBias,
18953
18958
  planId: ctx.planId,
18954
18959
  stepId: ctx.stepId,
@@ -18972,6 +18977,7 @@ var AffordanceSynthesizer = class {
18972
18977
  available: a.available,
18973
18978
  tags: a.tags,
18974
18979
  description: a.description,
18980
+ ...a.availability !== void 0 ? { availability: a.availability } : {},
18975
18981
  planBias: a.planBias,
18976
18982
  planId: a.planId,
18977
18983
  stepId: a.stepId,
@@ -19175,7 +19181,10 @@ var ActionSelector = class {
19175
19181
  ]
19176
19182
  }
19177
19183
  });
19178
- if (deliberating && rupture >= RUPTURE_REVOKE_GATE) {
19184
+ const policyRevoke = !!deliberating && refusedClassSchemas(state).has(deliberating.schema);
19185
+ if (deliberating && (rupture >= RUPTURE_REVOKE_GATE || policyRevoke)) {
19186
+ const reason = policyRevoke ? "policy-refusal" : "exafferent-rupture";
19187
+ const revRupture = policyRevoke ? Math.max(rupture, RUPTURE_REVOKE_GATE) : rupture;
19179
19188
  if (this._bus) {
19180
19189
  try {
19181
19190
  this._bus.publish({
@@ -19183,7 +19192,7 @@ var ActionSelector = class {
19183
19192
  version: 1,
19184
19193
  sourceEngine: this.name,
19185
19194
  salience: 0.85,
19186
- payload: { from: deliberating.schema, reason: "exafferent-rupture", rupture, tick }
19195
+ payload: { from: deliberating.schema, reason, rupture: revRupture, tick }
19187
19196
  });
19188
19197
  } catch (err) {
19189
19198
  logger.warn(`[selector] revoked publish failed: ${err instanceof Error ? err.message : String(err)}`);
@@ -19192,11 +19201,12 @@ var ActionSelector = class {
19192
19201
  this._lastRevoked = { schema: deliberating.schema, tick };
19193
19202
  return {
19194
19203
  commands: {
19195
- set: [revocationEntity(deliberating.id, deliberating.schema, rupture, tick)],
19204
+ set: [revocationEntity(deliberating.id, deliberating.schema, revRupture, tick)],
19196
19205
  metrics: [
19197
19206
  ["agency.field.eligible", eligible.length],
19198
19207
  ["agency.selection.busy", 1],
19199
19208
  ["agency.commitment.revoked", 1],
19209
+ ...policyRevoke ? [["agency.policy.revoked", 1]] : [],
19200
19210
  ...stabMetrics
19201
19211
  ]
19202
19212
  }
@@ -19407,6 +19417,17 @@ function computeRupture(state, tick, senseEvents = []) {
19407
19417
  if (maxSalience <= RUPTURE_SALIENCE_GATE) return 0;
19408
19418
  return clamp017((maxSalience - RUPTURE_SALIENCE_GATE) / (1 - RUPTURE_SALIENCE_GATE));
19409
19419
  }
19420
+ function refusedClassSchemas(state) {
19421
+ const out = /* @__PURE__ */ new Set();
19422
+ for (const e of state.entities.values()) {
19423
+ if (e.type !== "agency.outcome") continue;
19424
+ const m = e.metadata;
19425
+ if (m?.["refused"] !== true || str2(m?.["finality"]) !== "class") continue;
19426
+ const schema = str2(m?.["schema"]);
19427
+ if (schema) out.add(schema);
19428
+ }
19429
+ return out;
19430
+ }
19410
19431
  function effectiveWeights(state) {
19411
19432
  const p = readEffectiveParams(state, "engine-config-action-selector");
19412
19433
  return {
@@ -19794,6 +19815,7 @@ var MotorSchemaExecutor = class {
19794
19815
  }
19795
19816
  for (const [id, e] of state.entities) {
19796
19817
  if (e.type !== "agency.intent" || str5(e.metadata?.["status"]) !== "awaiting") continue;
19818
+ if (e.metadata?.["escalated"] === true) continue;
19797
19819
  const dispatchedAt = num3(e.metadata?.["dispatchedAt"], tick);
19798
19820
  if (tick - dispatchedAt < AWAIT_TIMEOUT) continue;
19799
19821
  const intent = readIntent(id, e.metadata);
@@ -20205,11 +20227,19 @@ var PROC_THRESHOLD = 0.6;
20205
20227
  var IDLE_TICKS = 200;
20206
20228
  var DECAY_RATE = 0.02;
20207
20229
  var DROP_HABIT = 0.05;
20230
+ var AVAIL_DROP_CLASS = 0.5;
20231
+ var AVAIL_DROP_INSTANCE = 0.12;
20232
+ var AVAIL_FLOOR = 0.05;
20233
+ var AVAIL_RECOVERY = 0.02;
20234
+ var AVAIL_RECOVERED = 0.999;
20208
20235
  var SchemaRepertoire = class {
20209
20236
  _templates = /* @__PURE__ */ new Map();
20210
20237
  _skills = /* @__PURE__ */ new Map();
20211
20238
  /** Tracks which templates were learned at runtime (vs innate) so decay can forget them. */
20212
20239
  _learned = /* @__PURE__ */ new Set();
20240
+ /** Availability layer (P2): schema → { value 0..1, lastRefusedTick }. Empty until
20241
+ * a refusal lands — a never-refused Will writes nothing here (byte-identical). */
20242
+ _availability = /* @__PURE__ */ new Map();
20213
20243
  constructor(seed = INNATE_SCHEMAS) {
20214
20244
  for (const s of seed) this._templates.set(s.id, s);
20215
20245
  }
@@ -20243,6 +20273,31 @@ var SchemaRepertoire = class {
20243
20273
  getSkill(id) {
20244
20274
  return this._skills.get(id);
20245
20275
  }
20276
+ // ── availability (P2) ─────────────────────────────────────────
20277
+ availability() {
20278
+ return this._availability;
20279
+ }
20280
+ /**
20281
+ * How available a schema is right now, 0..1. Absent from the ledger ⇒ 1
20282
+ * (fully available — the common case). This is the ONLY value the
20283
+ * AffordanceSynthesizer reads; it never touches competence.
20284
+ */
20285
+ availabilityOf(schema) {
20286
+ return this._availability.get(schema)?.value ?? 1;
20287
+ }
20288
+ /**
20289
+ * Fold a policy refusal into the availability layer (NOT competence). A
20290
+ * `class` refusal cuts availability hard; an `instance` refusal dents it
20291
+ * lightly. Multiplicative so repeated refusals compound toward — but never
20292
+ * reach — zero, keeping re-probe alive.
20293
+ */
20294
+ recordRefusal(schema, finality, tick) {
20295
+ const prev = this._availability.get(schema)?.value ?? 1;
20296
+ const drop = finality === "class" ? AVAIL_DROP_CLASS : AVAIL_DROP_INSTANCE;
20297
+ const value = Math.max(AVAIL_FLOOR, prev * (1 - drop));
20298
+ this._availability.set(schema, { value, lastRefusedTick: tick });
20299
+ return value;
20300
+ }
20246
20301
  /**
20247
20302
  * Fold one outcome into the schema's learned skill. Returns the updated skill
20248
20303
  * and whether it just crossed the proceduralization threshold this update.
@@ -20269,12 +20324,14 @@ var SchemaRepertoire = class {
20269
20324
  return { skill, proceduralized: !wasProceduralized && habitStrength >= PROC_THRESHOLD };
20270
20325
  }
20271
20326
  /**
20272
- * Forgetting curve over the competence layer. Skills unused for IDLE_TICKS
20273
- * lose habit; learned composites that fall below DROP_HABIT are dropped
20274
- * entirely (template + skill). Returns the schema ids that were forgotten.
20327
+ * Forgetting curve over the competence layer, plus availability recovery.
20328
+ * Skills unused for IDLE_TICKS lose habit; learned composites below DROP_HABIT
20329
+ * are dropped entirely (template + skill). Availability entries climb back
20330
+ * toward 1 and are dropped once fully recovered. Returns the ids that were
20331
+ * removed from each layer so their mirrored state entities can be deleted.
20275
20332
  */
20276
20333
  decay(tick) {
20277
- const dropped = [];
20334
+ const skills = [];
20278
20335
  for (const [id, skill] of this._skills) {
20279
20336
  if (tick - skill.lastEnactedTick <= IDLE_TICKS) continue;
20280
20337
  const habitStrength = clamp0110(skill.habitStrength - DECAY_RATE);
@@ -20282,12 +20339,20 @@ var SchemaRepertoire = class {
20282
20339
  this._skills.delete(id);
20283
20340
  this._templates.delete(id);
20284
20341
  this._learned.delete(id);
20285
- dropped.push(id);
20342
+ skills.push(id);
20286
20343
  continue;
20287
20344
  }
20288
20345
  this._skills.set(id, { ...skill, habitStrength });
20289
20346
  }
20290
- return dropped;
20347
+ const availability = [];
20348
+ for (const [id, avail] of this._availability) {
20349
+ const value = avail.value + AVAIL_RECOVERY * (1 - avail.value);
20350
+ if (value >= AVAIL_RECOVERED) {
20351
+ this._availability.delete(id);
20352
+ availability.push(id);
20353
+ } else this._availability.set(id, { ...avail, value });
20354
+ }
20355
+ return { skills, availability };
20291
20356
  }
20292
20357
  // ── PMA portability (Phase 6 reads these) ─────────────────────
20293
20358
  /** Learned composite templates + all skills above a confidence floor. */
@@ -20336,6 +20401,28 @@ var SchemaRepertoire = class {
20336
20401
  this._learned.add(s.id);
20337
20402
  }
20338
20403
  }
20404
+ /** Availability ledger encoded as `agency.availability` state entities (P2).
20405
+ * Empty until a refusal lands, so the quiet path writes nothing. */
20406
+ availabilityEntities() {
20407
+ const out = [];
20408
+ for (const [schema, a] of this._availability)
20409
+ out.push(availabilityEntity(schema, a.value, a.lastRefusedTick));
20410
+ return out;
20411
+ }
20412
+ /** Rehydrate the availability ledger from state after a restore. Idempotent;
20413
+ * keeps whichever value is more restrictive so a concurrent refusal isn't lost. */
20414
+ restoreAvailability(entities) {
20415
+ for (const e of entities.values()) {
20416
+ if (e.type !== AVAILABILITY_ENTITY_TYPE) continue;
20417
+ const m = e.metadata ?? {};
20418
+ const schema = typeof m["schema"] === "string" ? m["schema"] : "";
20419
+ if (!schema) continue;
20420
+ const value = typeof m["value"] === "number" ? m["value"] : 1;
20421
+ const tick = typeof m["lastRefusedTick"] === "number" ? m["lastRefusedTick"] : 0;
20422
+ const prev = this._availability.get(schema);
20423
+ if (!prev || value < prev.value) this._availability.set(schema, { value, lastRefusedTick: tick });
20424
+ }
20425
+ }
20339
20426
  };
20340
20427
  function freshSkill(schema, value, tick) {
20341
20428
  return {
@@ -20352,6 +20439,17 @@ function freshSkill(schema, value, tick) {
20352
20439
  function clamp0110(n) {
20353
20440
  return n < 0 ? 0 : n > 1 ? 1 : n;
20354
20441
  }
20442
+ var AVAILABILITY_ENTITY_TYPE = "agency.availability";
20443
+ function availabilityEntityId(schema) {
20444
+ return `agency-availability-${schema}`;
20445
+ }
20446
+ function availabilityEntity(schema, value, lastRefusedTick) {
20447
+ return {
20448
+ id: availabilityEntityId(schema),
20449
+ type: AVAILABILITY_ENTITY_TYPE,
20450
+ metadata: { schema, value, lastRefusedTick }
20451
+ };
20452
+ }
20355
20453
  var SCHEMA_ENTITY_TYPE = "agency.schema";
20356
20454
  function schemaEntityId(schemaId) {
20357
20455
  return `agency-schema-${schemaId}`;
@@ -20502,12 +20600,24 @@ var ReafferenceEngine = class {
20502
20600
  }
20503
20601
  let updates = 0;
20504
20602
  let discovered = 0;
20603
+ let refused = 0;
20505
20604
  for (const { id, meta: m, fromState } of outcomes) {
20506
20605
  const schema = str6(m["schema"]);
20507
20606
  if (!schema) {
20508
20607
  if (fromState) del.push(id);
20509
20608
  continue;
20510
20609
  }
20610
+ if (m["refused"] === true) {
20611
+ const finality = str6(m["finality"]) === "class" ? "class" : "instance";
20612
+ this._repertoire.recordRefusal(schema, finality, tick);
20613
+ if (fromState) del.push(id);
20614
+ const refusedIntent = str6(m["intentId"]);
20615
+ if (refusedIntent) del.push(refusedIntent);
20616
+ const refusedPlan = str6(m["planId"]);
20617
+ if (refusedPlan) this._emitPlanOutcome(refusedPlan, str6(m["stepId"]), schema, false, 0, 0, tick);
20618
+ refused++;
20619
+ continue;
20620
+ }
20511
20621
  const { skill, proceduralized } = this._repertoire.recordOutcome({
20512
20622
  schema,
20513
20623
  success: m["success"] === true,
@@ -20534,11 +20644,14 @@ var ReafferenceEngine = class {
20534
20644
  }
20535
20645
  }
20536
20646
  const dropped = this._repertoire.decay(tick);
20537
- for (const id of dropped) {
20647
+ for (const id of dropped.skills) {
20538
20648
  del.push(`agency-skill-${id}`);
20539
20649
  del.push(schemaEntityId(id));
20540
20650
  }
20651
+ for (const id of dropped.availability)
20652
+ del.push(availabilityEntityId(id));
20541
20653
  for (const e of this._repertoire.compositeEntities()) set.push(e);
20654
+ for (const e of this._repertoire.availabilityEntities()) set.push(e);
20542
20655
  const skills = this._repertoire.skills();
20543
20656
  const habitual = [...skills.values()].filter((s) => s.habitStrength >= PROC_THRESHOLD2).length;
20544
20657
  metrics.push(
@@ -20548,6 +20661,7 @@ var ReafferenceEngine = class {
20548
20661
  ["agency.habitual.count", habitual],
20549
20662
  ["agency.sensory.confirmed", sensory]
20550
20663
  );
20664
+ if (refused > 0) metrics.push(["agency.refused.count", refused]);
20551
20665
  return { commands: { set, delete: del, metrics } };
20552
20666
  }
20553
20667
  _emitProceduralized(skill, tick) {
@@ -25438,6 +25552,7 @@ function reconcileInvocation(intentId, schema, result, tick, predicted = { rewar
25438
25552
  mode: "external",
25439
25553
  tick,
25440
25554
  reconciled: true,
25555
+ ...result.refused ? { refused: true, finality: result.finality ?? "instance" } : {},
25441
25556
  ...provenance.planId ? { planId: provenance.planId } : {},
25442
25557
  ...provenance.stepId ? { stepId: provenance.stepId } : {}
25443
25558
  }
@@ -25447,8 +25562,56 @@ function clamp0112(n) {
25447
25562
  return n < 0 ? 0 : n > 1 ? 1 : n;
25448
25563
  }
25449
25564
 
25565
+ // src/stem/policy/arbiter.ts
25566
+ var ALLOW = Object.freeze({ decision: "allow" });
25567
+ var NULL_ARBITER = {
25568
+ name: "null",
25569
+ evaluate() {
25570
+ return ALLOW;
25571
+ }
25572
+ };
25573
+ function isNullArbiter(arbiter) {
25574
+ return !arbiter || arbiter === NULL_ARBITER;
25575
+ }
25576
+
25577
+ // src/stem/policy/verdict.recorder.ts
25578
+ var _sinks3 = /* @__PURE__ */ new Map();
25579
+ function getVerdictRecorder(willId) {
25580
+ return _sinks3.get(willId);
25581
+ }
25582
+ var _sources3 = /* @__PURE__ */ new Map();
25583
+ function getVerdictSource(willId) {
25584
+ return _sources3.get(willId);
25585
+ }
25586
+
25450
25587
  // src/stem/tracts/effector.controller.ts
25588
+ var ESCALATION_TTL_TICKS = 30;
25451
25589
  var effectorController = class {
25590
+ /** The Policy Decision Point consulted before an invocation reaches the world.
25591
+ * Defaults to the no-op arbiter, so an unconfigured Will is byte-identical. */
25592
+ _arbiter = NULL_ARBITER;
25593
+ /**
25594
+ * Denials queued during a step's flush, drained at the NEXT tick boundary
25595
+ * (POLICY_REAFFERENCE P1). Keyed by willId — harness state, exactly like
25596
+ * `pendingEffectorInvocations`; never simulation state, so it does not touch
25597
+ * `simulation.step` determinism and is regenerated on any re-execution.
25598
+ */
25599
+ _pendingRefusals = /* @__PURE__ */ new Map();
25600
+ /** Escalations awaiting their first application (mark intent + voice the ask). */
25601
+ _newEscalations = /* @__PURE__ */ new Map();
25602
+ /** Escalations currently held, keyed by intent id — the resolvable set. */
25603
+ _activeEscalations = /* @__PURE__ */ new Map();
25604
+ /** Host answers awaiting application at the next tick boundary. */
25605
+ _pendingResolutions = /* @__PURE__ */ new Map();
25606
+ /**
25607
+ * Install a Policy Decision Point (POLICY_REAFFERENCE P0). Passing null
25608
+ * restores the no-op default. The arbiter sees only the proposed act — never
25609
+ * simulation state — and its verdict decides whether the invocation is
25610
+ * handed to the host at all.
25611
+ */
25612
+ setArbiter(arbiter) {
25613
+ this._arbiter = arbiter ?? NULL_ARBITER;
25614
+ }
25452
25615
  /**
25453
25616
  * Update the set of allowed communication effectors at runtime via AccessGrants
25454
25617
  * (the permission / sense gate the senses + reply path read).
@@ -25464,6 +25627,224 @@ var effectorController = class {
25464
25627
  * echoes it on its result-ack, and `confirmExecution` uses it to find the intent.
25465
25628
  */
25466
25629
  bufferInvocation(instance, payload) {
25630
+ const willId = instance.config.id;
25631
+ const source = getVerdictSource(willId);
25632
+ if (source) {
25633
+ const invocation2 = toPolicyInvocation(instance, payload);
25634
+ const record = source.verdictFor(invocation2.tick, invocation2.intentId);
25635
+ if (record) this._applyVerdict(instance, payload, invocation2, recordToVerdict(record));
25636
+ else this._buffer(instance, payload);
25637
+ return;
25638
+ }
25639
+ if (isNullArbiter(this._arbiter)) {
25640
+ this._buffer(instance, payload);
25641
+ return;
25642
+ }
25643
+ const invocation = toPolicyInvocation(instance, payload);
25644
+ let verdict;
25645
+ try {
25646
+ verdict = this._arbiter.evaluate(invocation);
25647
+ } catch (err) {
25648
+ logger.error(`[policy] arbiter "${this._arbiter.name}" threw for "${invocation.schema}" \u2014 failing closed:`, err);
25649
+ return;
25650
+ }
25651
+ if (verdict instanceof Promise) {
25652
+ void verdict.then(
25653
+ (v) => this._recordAndApply(instance, payload, invocation, v),
25654
+ (err) => logger.error(`[policy] arbiter "${this._arbiter.name}" rejected for "${invocation.schema}" \u2014 failing closed:`, err)
25655
+ );
25656
+ return;
25657
+ }
25658
+ this._recordAndApply(instance, payload, invocation, verdict);
25659
+ }
25660
+ /** Capture the verdict on the tape (if a recorder is attached), then enforce it. */
25661
+ _recordAndApply(instance, payload, invocation, verdict) {
25662
+ const sink = getVerdictRecorder(instance.config.id);
25663
+ sink?.recordVerdict({
25664
+ tick: invocation.tick,
25665
+ willId: instance.config.id,
25666
+ intentId: invocation.intentId,
25667
+ schema: invocation.schema,
25668
+ arbiter: this._arbiter.name,
25669
+ decision: verdict.decision,
25670
+ ...verdict.reasonCode ? { reasonCode: verdict.reasonCode } : {},
25671
+ ...verdict.finality ? { finality: verdict.finality } : {},
25672
+ ...verdict.counterfactual ? { counterfactual: verdict.counterfactual } : {},
25673
+ timestamp: Date.now()
25674
+ });
25675
+ this._applyVerdict(instance, payload, invocation, verdict);
25676
+ }
25677
+ /**
25678
+ * Enforce a verdict (POLICY_REAFFERENCE P1).
25679
+ *
25680
+ * • allow → hand the invocation to the world.
25681
+ * • deny → queue a refusal ack, applied at the next tick boundary via
25682
+ * `confirmExecution` — the same lifecycle as a host rejection,
25683
+ * so the mind meets *world resistance*, not a permission dialog.
25684
+ * • escalate → raise a held escalation (POLICY_REAFFERENCE P4): the intent is
25685
+ * held (the executor stops timing it out), the Will voices a
25686
+ * first-person ask once, and a host resolution later approves
25687
+ * (dispatch) or denies (refuse). Unresolved, it degrades to a
25688
+ * refusal at ESCALATION_TTL_TICKS.
25689
+ *
25690
+ * P1's refusal reconciles as a plain FAILURE — safe, but the wrong learning
25691
+ * signal (forbidden ≠ unskilled). P2 routes it to affordance AVAILABILITY
25692
+ * instead of competence.
25693
+ */
25694
+ _applyVerdict(instance, payload, invocation, verdict) {
25695
+ if (verdict.decision === "allow") {
25696
+ this._buffer(instance, payload);
25697
+ return;
25698
+ }
25699
+ const cf = verdict.counterfactual;
25700
+ logger.info(
25701
+ `[policy] ${verdict.decision.toUpperCase()} "${invocation.schema}" intent "${invocation.intentId}" \u2014 ${verdict.reasonCode ?? "no reason code"}` + (verdict.finality ? ` (${verdict.finality})` : "") + (cf ? ` [${cf.field}: requested ${JSON.stringify(cf.requested)}, allowed ${JSON.stringify(cf.allowed)}]` : "")
25702
+ );
25703
+ if (verdict.decision === "deny") {
25704
+ const queue = this._pendingRefusals.get(instance.config.id) ?? [];
25705
+ queue.push({
25706
+ intentId: invocation.intentId,
25707
+ schema: invocation.schema,
25708
+ reasonCode: verdict.reasonCode ?? "POLICY_DENIED",
25709
+ finality: verdict.finality ?? "instance"
25710
+ });
25711
+ this._pendingRefusals.set(instance.config.id, queue);
25712
+ return;
25713
+ }
25714
+ const escalations = this._newEscalations.get(instance.config.id) ?? [];
25715
+ escalations.push({
25716
+ intentId: invocation.intentId,
25717
+ schema: invocation.schema,
25718
+ reasonCode: verdict.reasonCode ?? "APPROVAL_REQUIRED",
25719
+ payload,
25720
+ expiresAt: 0
25721
+ // stamped when applied (we don't have the current tick here)
25722
+ });
25723
+ this._newEscalations.set(instance.config.id, escalations);
25724
+ }
25725
+ /**
25726
+ * Record a host's answer to an escalation (POLICY_REAFFERENCE P4). Applied at
25727
+ * the next tick boundary so every simulation-state write stays on the boundary:
25728
+ * approve dispatches the held invocation to the world; deny refuses it. A
25729
+ * no-op if the intent id is not (or no longer) an active escalation.
25730
+ */
25731
+ resolveEscalation(instance, intentId, approved) {
25732
+ const queue = this._pendingResolutions.get(instance.config.id) ?? [];
25733
+ queue.push({ intentId, approved });
25734
+ this._pendingResolutions.set(instance.config.id, queue);
25735
+ }
25736
+ /**
25737
+ * Apply queued policy refusals as failure acks (POLICY_REAFFERENCE P1).
25738
+ * Called by the tick loop at the same boundary as inbound acks — BEFORE the
25739
+ * step, stamped to this tick — so a denial reconciled here is the exact
25740
+ * lifecycle of a host rejection that arrived between ticks.
25741
+ */
25742
+ applyPolicyOutcomes(instance) {
25743
+ const tick = instance.tickCount;
25744
+ this._applyResolutions(instance);
25745
+ this._expireEscalations(instance, tick);
25746
+ this._applyNewEscalations(instance, tick);
25747
+ this._applyRefusals(instance);
25748
+ }
25749
+ /** Drain queued refusals into failure acks (POLICY_REAFFERENCE P1). */
25750
+ _applyRefusals(instance) {
25751
+ const queue = this._pendingRefusals.get(instance.config.id);
25752
+ if (!queue || queue.length === 0) return;
25753
+ this._pendingRefusals.set(instance.config.id, []);
25754
+ for (const refusal of queue)
25755
+ this.confirmExecution(instance, refusal.intentId, {
25756
+ success: false,
25757
+ refused: true,
25758
+ finality: refusal.finality === "class" ? "class" : "instance",
25759
+ description: `refused by policy: ${refusal.reasonCode} (${refusal.finality})`
25760
+ });
25761
+ }
25762
+ /** Raise each newly-escalated intent (POLICY_REAFFERENCE P4): mark it held in
25763
+ * simulation state, voice the ask ONCE, and move it to the resolvable set. */
25764
+ _applyNewEscalations(instance, tick) {
25765
+ const pending = this._newEscalations.get(instance.config.id);
25766
+ if (!pending || pending.length === 0) return;
25767
+ this._newEscalations.set(instance.config.id, []);
25768
+ const active = this._activeEscalations.get(instance.config.id) ?? /* @__PURE__ */ new Map();
25769
+ for (const esc of pending) {
25770
+ esc.expiresAt = tick + ESCALATION_TTL_TICKS;
25771
+ this._markEscalated(instance, esc.intentId, esc.expiresAt);
25772
+ this._voiceEscalation(instance, esc);
25773
+ active.set(esc.intentId, esc);
25774
+ }
25775
+ this._activeEscalations.set(instance.config.id, active);
25776
+ }
25777
+ /** Apply host answers to active escalations (POLICY_REAFFERENCE P4). */
25778
+ _applyResolutions(instance) {
25779
+ const queue = this._pendingResolutions.get(instance.config.id);
25780
+ if (!queue || queue.length === 0) return;
25781
+ this._pendingResolutions.set(instance.config.id, []);
25782
+ const active = this._activeEscalations.get(instance.config.id);
25783
+ for (const { intentId, approved } of queue) {
25784
+ const esc = active?.get(intentId);
25785
+ if (!esc) continue;
25786
+ active.delete(intentId);
25787
+ this._clearEscalated(instance, intentId);
25788
+ if (approved) {
25789
+ this._buffer(instance, esc.payload);
25790
+ logger.info(`[policy] escalation APPROVED \u2192 dispatching "${esc.schema}" intent "${intentId}"`);
25791
+ } else {
25792
+ this._queueRefusal(instance, esc.intentId, esc.schema, esc.reasonCode, "class");
25793
+ logger.info(`[policy] escalation DENIED \u2192 refusing "${esc.schema}" intent "${intentId}"`);
25794
+ }
25795
+ }
25796
+ }
25797
+ /** Degrade escalations no one answered in time into instance-refusals (P4). */
25798
+ _expireEscalations(instance, tick) {
25799
+ const active = this._activeEscalations.get(instance.config.id);
25800
+ if (!active || active.size === 0) return;
25801
+ for (const [intentId, esc] of active) {
25802
+ if (tick < esc.expiresAt) continue;
25803
+ active.delete(intentId);
25804
+ this._clearEscalated(instance, intentId);
25805
+ this._queueRefusal(instance, esc.intentId, esc.schema, "ESCALATION_EXPIRED", "instance");
25806
+ logger.info(`[policy] escalation EXPIRED \u2192 refusing "${esc.schema}" intent "${intentId}"`);
25807
+ }
25808
+ }
25809
+ /** Push a refusal onto the queue drained by _applyRefusals this same tick. */
25810
+ _queueRefusal(instance, intentId, schema, reasonCode, finality) {
25811
+ const queue = this._pendingRefusals.get(instance.config.id) ?? [];
25812
+ queue.push({ intentId, schema, reasonCode, finality });
25813
+ this._pendingRefusals.set(instance.config.id, queue);
25814
+ }
25815
+ /** Mark the awaiting intent held: the executor stops timing it out (P4). */
25816
+ _markEscalated(instance, intentId, expiresAt) {
25817
+ const intent = instance.simulation.stateManager.snapshot().entities.get(intentId);
25818
+ if (!intent || intent.type !== "agency.intent") return;
25819
+ instance.simulation.stateManager.setEntity({
25820
+ id: intent.id,
25821
+ type: intent.type,
25822
+ metadata: { ...intent.metadata ?? {}, escalated: true, escalationExpiresAt: expiresAt }
25823
+ });
25824
+ }
25825
+ /** Release the hold so the executor resumes normal timeout for this intent. */
25826
+ _clearEscalated(instance, intentId) {
25827
+ const intent = instance.simulation.stateManager.snapshot().entities.get(intentId);
25828
+ if (!intent || intent.type !== "agency.intent") return;
25829
+ const meta = { ...intent.metadata ?? {} };
25830
+ delete meta["escalated"];
25831
+ delete meta["escalationExpiresAt"];
25832
+ instance.simulation.stateManager.setEntity({ id: intent.id, type: intent.type, metadata: meta });
25833
+ }
25834
+ /** Voice the escalation as a first-person broadcast ask — once, at raise time. */
25835
+ _voiceEscalation(instance, esc) {
25836
+ try {
25837
+ instance.cognition.outboxWriter.enqueue({
25838
+ targetEntityId: "*",
25839
+ content: escalationAsk(esc.schema, esc.reasonCode),
25840
+ effectorName: "broadcast"
25841
+ });
25842
+ } catch (err) {
25843
+ logger.warn(`[policy] escalation voice failed for "${esc.schema}": ${errMsg2(err)}`);
25844
+ }
25845
+ }
25846
+ /** Queue an approved invocation for the delivery layer. */
25847
+ _buffer(instance, payload) {
25467
25848
  const intentId = payload.intentId ?? "";
25468
25849
  instance.pendingEffectorInvocations.push({
25469
25850
  id: intentId,
@@ -25538,6 +25919,38 @@ var effectorController = class {
25538
25919
  function num5(v, fallback) {
25539
25920
  return typeof v === "number" && Number.isFinite(v) ? v : fallback;
25540
25921
  }
25922
+ function escalationAsk(schema, reasonCode) {
25923
+ const meaning = ESCALATION_MEANINGS[reasonCode] ?? "I need your approval before I can do this";
25924
+ return `I want to ${schema}, but ${meaning}. May I go ahead?`;
25925
+ }
25926
+ var ESCALATION_MEANINGS = {
25927
+ APPROVAL_REQUIRED: "I need your approval before I can on my own",
25928
+ WRITE_REQUIRES_APPROVAL: "it writes to the world and I shouldn't on my own",
25929
+ PAYMENT_REQUIRES_APPROVAL: "it moves money and I must not do that unattended",
25930
+ DEPLOY_REQUIRES_APPROVAL: "it ships something and needs a human to sign off"
25931
+ };
25932
+ function errMsg2(err) {
25933
+ return err instanceof Error ? err.message : String(err);
25934
+ }
25935
+ function recordToVerdict(record) {
25936
+ return {
25937
+ decision: record.decision,
25938
+ ...record.reasonCode ? { reasonCode: record.reasonCode } : {},
25939
+ ...record.finality ? { finality: record.finality } : {},
25940
+ ...record.counterfactual ? { counterfactual: record.counterfactual } : {}
25941
+ };
25942
+ }
25943
+ function toPolicyInvocation(instance, payload) {
25944
+ return {
25945
+ willId: instance.config.id,
25946
+ intentId: payload.intentId ?? "",
25947
+ schema: payload.schema ?? "",
25948
+ parameters: payload.parameters ?? {},
25949
+ ...typeof payload.targetEntityId === "string" ? { targetEntityId: payload.targetEntityId } : {},
25950
+ ...typeof payload.description === "string" ? { description: payload.description } : {},
25951
+ tick: payload.tick ?? 0
25952
+ };
25953
+ }
25541
25954
 
25542
25955
  // src/stem/tracts/sensory.controller.ts
25543
25956
  var SensoryController = class {
@@ -26340,6 +26753,15 @@ var WillStem = class {
26340
26753
  confirmEffectorExecution(id, invocationId, result) {
26341
26754
  this._effector.confirmExecution(this._get(id), invocationId, result);
26342
26755
  }
26756
+ /**
26757
+ * Resolve a policy escalation the Will raised (POLICY_REAFFERENCE P4).
26758
+ * `approved` dispatches the held invocation to the world; otherwise it is
26759
+ * refused. Applied at the next tick boundary. `invocationId` is the awaiting
26760
+ * `agency.intent` id the escalation ask referenced.
26761
+ */
26762
+ resolveEscalation(id, invocationId, approved) {
26763
+ this._effector.resolveEscalation(this._get(id), invocationId, approved);
26764
+ }
26343
26765
  // ── Messaging / outbox (11.1) ────────────────────────────────────────────
26344
26766
  // Delegates to OutboxController (R5-c). `_get(id)` validates the Will exists
26345
26767
  // and supplies the WillInstance; the outbox ops touch only instance fields.
@@ -26470,6 +26892,7 @@ var WillStem = class {
26470
26892
  outbox: this._outbox,
26471
26893
  sensory: this._sensory
26472
26894
  });
26895
+ this._effector.applyPolicyOutcomes(instance);
26473
26896
  await instance.simulation.step(1);
26474
26897
  instance.tickCount++;
26475
26898
  instance.lastTickAt = /* @__PURE__ */ new Date();