@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/channels/discord.d.ts +1 -1
- package/dist/channels/whatsapp.d.ts +1 -1
- package/dist/cli.js +434 -11
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +434 -11
- package/dist/index.js.map +1 -1
- package/dist/mcp/effectors.d.ts +1 -1
- package/dist/{will-Bikuk4s2.d.ts → will-DAW0l-lY.d.ts} +42 -4
- package/package.json +1 -1
- package/src/cognition/agency/engines/action.selector.ts +41 -9
- package/src/cognition/agency/engines/affordance.synthesizer.ts +9 -0
- package/src/cognition/agency/engines/motor.schema.executor.ts +4 -0
- package/src/cognition/agency/engines/reafference.engine.ts +30 -5
- package/src/cognition/agency/reconcile.learning.ts +9 -0
- package/src/cognition/agency/schemas/repertoire.ts +107 -7
- package/src/cognition/agency/selection.scoring.ts +7 -1
- package/src/cognition/agency/types.ts +9 -0
- package/src/stem/index.ts +15 -0
- package/src/stem/policy/arbiter.ts +136 -0
- package/src/stem/policy/rule.table.ts +172 -0
- package/src/stem/policy/verdict.recorder.ts +0 -0
- package/src/stem/tracts/effector.controller.ts +379 -0
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-
|
|
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-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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,
|
|
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
|
|
20273
|
-
* lose habit; learned composites
|
|
20274
|
-
* entirely (template + skill).
|
|
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
|
|
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
|
-
|
|
20342
|
+
skills.push(id);
|
|
20286
20343
|
continue;
|
|
20287
20344
|
}
|
|
20288
20345
|
this._skills.set(id, { ...skill, habitStrength });
|
|
20289
20346
|
}
|
|
20290
|
-
|
|
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();
|