@almadar/std 1.0.15 → 2.1.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.js CHANGED
@@ -10,7 +10,8 @@ var STD_MODULES = [
10
10
  "async",
11
11
  "nn",
12
12
  "tensor",
13
- "train"
13
+ "train",
14
+ "prob"
14
15
  ];
15
16
  var STD_OPERATOR_CATEGORIES = [
16
17
  "std-math",
@@ -23,7 +24,8 @@ var STD_OPERATOR_CATEGORIES = [
23
24
  "std-async",
24
25
  "std-nn",
25
26
  "std-tensor",
26
- "std-train"
27
+ "std-train",
28
+ "std-prob"
27
29
  ];
28
30
  function isStdCategory(category) {
29
31
  return STD_OPERATOR_CATEGORIES.includes(category);
@@ -2142,12 +2144,29 @@ var ASYNC_OPERATORS = {
2142
2144
  module: "async",
2143
2145
  category: "std-async",
2144
2146
  minArity: 1,
2145
- maxArity: 1,
2146
- description: "Wait for specified milliseconds",
2147
+ maxArity: 2,
2148
+ description: "Wait for specified milliseconds, optionally execute an effect after",
2147
2149
  hasSideEffects: true,
2148
- returnType: "void",
2149
- params: [{ name: "ms", type: "number", description: "Milliseconds to wait" }],
2150
- example: '["async/delay", 2000] // Wait 2 seconds'
2150
+ returnType: "any",
2151
+ params: [
2152
+ { name: "ms", type: "number", description: "Milliseconds to wait" },
2153
+ { name: "effect", type: "expression", description: "Optional effect to execute after delay" }
2154
+ ],
2155
+ example: '["async/delay", 2000, ["emit", "RETRY"]] // Wait 2s then emit'
2156
+ },
2157
+ "async/interval": {
2158
+ module: "async",
2159
+ category: "std-async",
2160
+ minArity: 2,
2161
+ maxArity: 2,
2162
+ description: "Execute an effect periodically at a fixed interval",
2163
+ hasSideEffects: true,
2164
+ returnType: "string",
2165
+ params: [
2166
+ { name: "ms", type: "number", description: "Interval in milliseconds" },
2167
+ { name: "effect", type: "expression", description: "Effect to execute each interval" }
2168
+ ],
2169
+ example: '["async/interval", 5000, ["emit", "POLL_TICK"]] // Emit every 5s'
2151
2170
  },
2152
2171
  "async/timeout": {
2153
2172
  module: "async",
@@ -3148,6 +3167,229 @@ var TRAIN_OPERATORS = {
3148
3167
  }
3149
3168
  };
3150
3169
 
3170
+ // modules/prob.ts
3171
+ var PROB_OPERATORS = {
3172
+ // ========================================
3173
+ // Distribution Sampling
3174
+ // ========================================
3175
+ "prob/seed": {
3176
+ module: "prob",
3177
+ category: "std-prob",
3178
+ minArity: 1,
3179
+ maxArity: 1,
3180
+ description: "Set seeded PRNG for deterministic probabilistic sampling",
3181
+ hasSideEffects: true,
3182
+ returnType: "void",
3183
+ params: [{ name: "n", type: "number", description: "Seed value (integer)" }],
3184
+ example: '["prob/seed", 42]'
3185
+ },
3186
+ "prob/flip": {
3187
+ module: "prob",
3188
+ category: "std-prob",
3189
+ minArity: 1,
3190
+ maxArity: 1,
3191
+ description: "Bernoulli trial: returns true with probability p",
3192
+ hasSideEffects: false,
3193
+ returnType: "boolean",
3194
+ params: [{ name: "p", type: "number", description: "Probability of true (0 to 1)" }],
3195
+ example: '["prob/flip", 0.5] // => true or false with equal probability'
3196
+ },
3197
+ "prob/gaussian": {
3198
+ module: "prob",
3199
+ category: "std-prob",
3200
+ minArity: 2,
3201
+ maxArity: 2,
3202
+ description: "Sample from a Gaussian (normal) distribution",
3203
+ hasSideEffects: false,
3204
+ returnType: "number",
3205
+ params: [
3206
+ { name: "mu", type: "number", description: "Mean" },
3207
+ { name: "sigma", type: "number", description: "Standard deviation" }
3208
+ ],
3209
+ example: '["prob/gaussian", 0, 1] // => standard normal sample'
3210
+ },
3211
+ "prob/uniform": {
3212
+ module: "prob",
3213
+ category: "std-prob",
3214
+ minArity: 2,
3215
+ maxArity: 2,
3216
+ description: "Sample from a uniform distribution [lo, hi)",
3217
+ hasSideEffects: false,
3218
+ returnType: "number",
3219
+ params: [
3220
+ { name: "lo", type: "number", description: "Lower bound (inclusive)" },
3221
+ { name: "hi", type: "number", description: "Upper bound (exclusive)" }
3222
+ ],
3223
+ example: '["prob/uniform", 0, 10] // => number in [0, 10)'
3224
+ },
3225
+ "prob/beta": {
3226
+ module: "prob",
3227
+ category: "std-prob",
3228
+ minArity: 2,
3229
+ maxArity: 2,
3230
+ description: "Sample from a Beta(alpha, beta) distribution",
3231
+ hasSideEffects: false,
3232
+ returnType: "number",
3233
+ params: [
3234
+ { name: "alpha", type: "number", description: "Alpha shape parameter (> 0)" },
3235
+ { name: "beta", type: "number", description: "Beta shape parameter (> 0)" }
3236
+ ],
3237
+ example: '["prob/beta", 2, 5] // => number in [0, 1], mean ~ 0.286'
3238
+ },
3239
+ "prob/categorical": {
3240
+ module: "prob",
3241
+ category: "std-prob",
3242
+ minArity: 2,
3243
+ maxArity: 2,
3244
+ description: "Weighted random selection from items",
3245
+ hasSideEffects: false,
3246
+ returnType: "any",
3247
+ params: [
3248
+ { name: "items", type: "array", description: "Array of items to choose from" },
3249
+ { name: "weights", type: "number[]", description: "Array of weights (same length as items)" }
3250
+ ],
3251
+ example: '["prob/categorical", ["a", "b", "c"], [1, 2, 1]] // => "b" most likely'
3252
+ },
3253
+ "prob/poisson": {
3254
+ module: "prob",
3255
+ category: "std-prob",
3256
+ minArity: 1,
3257
+ maxArity: 1,
3258
+ description: "Sample from a Poisson distribution",
3259
+ hasSideEffects: false,
3260
+ returnType: "number",
3261
+ params: [{ name: "lambda", type: "number", description: "Rate parameter (> 0)" }],
3262
+ example: '["prob/poisson", 4] // => non-negative integer, mean ~ 4'
3263
+ },
3264
+ // ========================================
3265
+ // Inference
3266
+ // ========================================
3267
+ "prob/condition": {
3268
+ module: "prob",
3269
+ category: "std-prob",
3270
+ minArity: 1,
3271
+ maxArity: 1,
3272
+ description: "Mark current sample as rejected if predicate is false",
3273
+ hasSideEffects: true,
3274
+ returnType: "void",
3275
+ params: [{ name: "predicate", type: "boolean", description: "Condition that must hold" }],
3276
+ example: '["prob/condition", [">", "@entity.x", 0]]'
3277
+ },
3278
+ "prob/sample": {
3279
+ module: "prob",
3280
+ category: "std-prob",
3281
+ minArity: 2,
3282
+ maxArity: 2,
3283
+ description: "Evaluate an expression n times and collect results",
3284
+ hasSideEffects: false,
3285
+ returnType: "array",
3286
+ params: [
3287
+ { name: "n", type: "number", description: "Number of samples" },
3288
+ { name: "expr", type: "SExpr", description: "Expression to evaluate (lazy)" }
3289
+ ],
3290
+ example: '["prob/sample", 1000, ["prob/flip", 0.5]] // => array of booleans'
3291
+ },
3292
+ "prob/posterior": {
3293
+ module: "prob",
3294
+ category: "std-prob",
3295
+ minArity: 4,
3296
+ maxArity: 4,
3297
+ description: "Rejection sampling: returns accepted query values",
3298
+ hasSideEffects: false,
3299
+ returnType: "array",
3300
+ params: [
3301
+ { name: "model", type: "SExpr", description: "Model expression (lazy, may call set/condition)" },
3302
+ { name: "evidence", type: "SExpr", description: "Evidence expression (lazy, boolean)" },
3303
+ { name: "query", type: "SExpr", description: "Query expression (lazy, value to collect)" },
3304
+ { name: "n", type: "number", description: "Number of samples to attempt" }
3305
+ ],
3306
+ example: '["prob/posterior", model, evidence, query, 5000]'
3307
+ },
3308
+ "prob/infer": {
3309
+ module: "prob",
3310
+ category: "std-prob",
3311
+ minArity: 4,
3312
+ maxArity: 4,
3313
+ description: "Like posterior but returns {mean, variance, samples, acceptRate}",
3314
+ hasSideEffects: false,
3315
+ returnType: "object",
3316
+ params: [
3317
+ { name: "model", type: "SExpr", description: "Model expression (lazy)" },
3318
+ { name: "evidence", type: "SExpr", description: "Evidence expression (lazy, boolean)" },
3319
+ { name: "query", type: "SExpr", description: "Query expression (lazy)" },
3320
+ { name: "n", type: "number", description: "Number of samples to attempt" }
3321
+ ],
3322
+ example: '["prob/infer", model, evidence, query, 5000]'
3323
+ },
3324
+ // ========================================
3325
+ // Statistics
3326
+ // ========================================
3327
+ "prob/expected-value": {
3328
+ module: "prob",
3329
+ category: "std-prob",
3330
+ minArity: 1,
3331
+ maxArity: 1,
3332
+ description: "Mean of numeric samples",
3333
+ hasSideEffects: false,
3334
+ returnType: "number",
3335
+ params: [{ name: "samples", type: "number[]", description: "Array of numeric samples" }],
3336
+ example: '["prob/expected-value", [2, 4, 6, 8]] // => 5'
3337
+ },
3338
+ "prob/variance": {
3339
+ module: "prob",
3340
+ category: "std-prob",
3341
+ minArity: 1,
3342
+ maxArity: 1,
3343
+ description: "Population variance of numeric samples",
3344
+ hasSideEffects: false,
3345
+ returnType: "number",
3346
+ params: [{ name: "samples", type: "number[]", description: "Array of numeric samples" }],
3347
+ example: '["prob/variance", [2, 4, 4, 4, 5, 5, 7, 9]] // => 4'
3348
+ },
3349
+ "prob/histogram": {
3350
+ module: "prob",
3351
+ category: "std-prob",
3352
+ minArity: 2,
3353
+ maxArity: 2,
3354
+ description: "Bin numeric samples into a histogram",
3355
+ hasSideEffects: false,
3356
+ returnType: "object",
3357
+ params: [
3358
+ { name: "samples", type: "number[]", description: "Array of numeric samples" },
3359
+ { name: "bins", type: "number", description: "Number of bins" }
3360
+ ],
3361
+ example: '["prob/histogram", [1, 2, 3, 4, 5], 2] // => {binEdges, counts}'
3362
+ },
3363
+ "prob/percentile": {
3364
+ module: "prob",
3365
+ category: "std-prob",
3366
+ minArity: 2,
3367
+ maxArity: 2,
3368
+ description: "Get the p-th percentile (0-100) from samples",
3369
+ hasSideEffects: false,
3370
+ returnType: "number",
3371
+ params: [
3372
+ { name: "samples", type: "number[]", description: "Array of numeric samples" },
3373
+ { name: "p", type: "number", description: "Percentile (0 to 100)" }
3374
+ ],
3375
+ example: '["prob/percentile", [1, 2, 3, 4, 5], 50] // => 3'
3376
+ },
3377
+ "prob/credible-interval": {
3378
+ module: "prob",
3379
+ category: "std-prob",
3380
+ minArity: 2,
3381
+ maxArity: 2,
3382
+ description: "Compute symmetric credible interval from samples",
3383
+ hasSideEffects: false,
3384
+ returnType: "array",
3385
+ params: [
3386
+ { name: "samples", type: "number[]", description: "Array of numeric samples" },
3387
+ { name: "alpha", type: "number", description: "Significance level (e.g., 0.05 for 95% interval)" }
3388
+ ],
3389
+ example: '["prob/credible-interval", samples, 0.05] // => [lo, hi]'
3390
+ }
3391
+ };
3392
+
3151
3393
  // registry.ts
3152
3394
  var STD_OPERATORS = {
3153
3395
  ...MATH_OPERATORS,
@@ -3160,7 +3402,8 @@ var STD_OPERATORS = {
3160
3402
  ...ASYNC_OPERATORS,
3161
3403
  ...NN_OPERATORS,
3162
3404
  ...TENSOR_OPERATORS,
3163
- ...TRAIN_OPERATORS
3405
+ ...TRAIN_OPERATORS,
3406
+ ...PROB_OPERATORS
3164
3407
  };
3165
3408
  var STD_OPERATORS_BY_MODULE = {
3166
3409
  math: MATH_OPERATORS,
@@ -3173,7 +3416,8 @@ var STD_OPERATORS_BY_MODULE = {
3173
3416
  async: ASYNC_OPERATORS,
3174
3417
  nn: NN_OPERATORS,
3175
3418
  tensor: TENSOR_OPERATORS,
3176
- train: TRAIN_OPERATORS
3419
+ train: TRAIN_OPERATORS,
3420
+ prob: PROB_OPERATORS
3177
3421
  };
3178
3422
  function getStdOperatorMeta(operator) {
3179
3423
  return STD_OPERATORS[operator];
@@ -7696,84 +7940,1022 @@ var GAME_UI_BEHAVIORS = [
7696
7940
  LEVEL_PROGRESS_BEHAVIOR
7697
7941
  ];
7698
7942
 
7699
- // behaviors/registry.ts
7700
- var STANDARD_BEHAVIORS = [
7701
- ...UI_INTERACTION_BEHAVIORS,
7702
- ...DATA_MANAGEMENT_BEHAVIORS,
7703
- ...ASYNC_BEHAVIORS,
7704
- ...FEEDBACK_BEHAVIORS,
7705
- ...GAME_CORE_BEHAVIORS,
7706
- ...GAME_ENTITY_BEHAVIORS,
7707
- ...GAME_UI_BEHAVIORS
7708
- ];
7709
- var BEHAVIOR_REGISTRY = STANDARD_BEHAVIORS.reduce(
7710
- (acc, behavior) => {
7711
- acc[behavior.name] = behavior;
7712
- return acc;
7713
- },
7714
- {}
7715
- );
7716
- function getBehavior(name) {
7717
- return BEHAVIOR_REGISTRY[name];
7718
- }
7719
- function isKnownBehavior(name) {
7720
- return name in BEHAVIOR_REGISTRY;
7721
- }
7722
- function getAllBehaviorNames() {
7723
- return Object.keys(BEHAVIOR_REGISTRY);
7724
- }
7725
- function getAllBehaviors() {
7726
- return STANDARD_BEHAVIORS;
7727
- }
7728
- function getAllBehaviorMetadata() {
7729
- return STANDARD_BEHAVIORS.map(getBehaviorMetadata);
7730
- }
7731
- function findBehaviorsForUseCase(useCase) {
7732
- const lowerUseCase = useCase.toLowerCase();
7733
- return STANDARD_BEHAVIORS.filter(
7734
- (behavior) => behavior.description?.toLowerCase().includes(lowerUseCase) ?? false
7735
- );
7736
- }
7737
- function getBehaviorsForEvent(event) {
7738
- return STANDARD_BEHAVIORS.filter((behavior) => {
7739
- for (const orbital of behavior.orbitals || []) {
7740
- for (const trait of orbital.traits || []) {
7741
- if (typeof trait === "object" && "stateMachine" in trait) {
7742
- const events = trait.stateMachine?.events || [];
7743
- if (events.some((e) => e.key === event)) {
7744
- return true;
7745
- }
7746
- }
7747
- }
7748
- }
7749
- return false;
7750
- });
7751
- }
7752
- function getBehaviorsWithState(state) {
7753
- return STANDARD_BEHAVIORS.filter((behavior) => {
7754
- for (const orbital of behavior.orbitals || []) {
7755
- for (const trait of orbital.traits || []) {
7756
- if (typeof trait === "object" && "stateMachine" in trait) {
7757
- const states = trait.stateMachine?.states || [];
7758
- if (states.some((s) => s.name === state)) {
7759
- return true;
7760
- }
7943
+ // behaviors/infrastructure.ts
7944
+ var CIRCUIT_BREAKER_BEHAVIOR = {
7945
+ name: "std-circuit-breaker",
7946
+ version: "1.0.0",
7947
+ description: "Circuit breaker pattern with automatic recovery",
7948
+ orbitals: [
7949
+ {
7950
+ name: "CircuitBreakerOrbital",
7951
+ entity: {
7952
+ name: "CircuitBreakerState",
7953
+ persistence: "runtime",
7954
+ fields: [
7955
+ { name: "id", type: "string", required: true },
7956
+ { name: "circuitState", type: "string", default: "closed" },
7957
+ { name: "errorCount", type: "number", default: 0 },
7958
+ { name: "errorRate", type: "number", default: 0 },
7959
+ { name: "successCount", type: "number", default: 0 },
7960
+ { name: "totalCount", type: "number", default: 0 },
7961
+ { name: "lastFailure", type: "number", default: null },
7962
+ { name: "lastSuccess", type: "number", default: null },
7963
+ { name: "errorThreshold", type: "number", default: 5 },
7964
+ { name: "errorRateThreshold", type: "number", default: 0.5 },
7965
+ { name: "resetAfterMs", type: "number", default: 6e4 },
7966
+ { name: "halfOpenMaxAttempts", type: "number", default: 3 },
7967
+ { name: "halfOpenAttempts", type: "number", default: 0 }
7968
+ ]
7969
+ },
7970
+ traits: [
7971
+ {
7972
+ name: "CircuitBreaker",
7973
+ linkedEntity: "CircuitBreakerState",
7974
+ category: "lifecycle",
7975
+ emits: [
7976
+ { event: "CIRCUIT_OPENED", scope: "external" },
7977
+ { event: "CIRCUIT_CLOSED", scope: "external" },
7978
+ { event: "CIRCUIT_HALF_OPEN", scope: "external" }
7979
+ ],
7980
+ stateMachine: {
7981
+ states: [
7982
+ { name: "Closed", isInitial: true },
7983
+ { name: "Open" },
7984
+ { name: "HalfOpen" }
7985
+ ],
7986
+ events: [
7987
+ { key: "RECORD_SUCCESS", name: "Record Success" },
7988
+ { key: "RECORD_FAILURE", name: "Record Failure" },
7989
+ { key: "PROBE", name: "Probe" },
7990
+ { key: "RESET", name: "Reset" }
7991
+ ],
7992
+ transitions: [
7993
+ // Closed: record success
7994
+ {
7995
+ from: "Closed",
7996
+ to: "Closed",
7997
+ event: "RECORD_SUCCESS",
7998
+ effects: [
7999
+ ["set", "@entity.successCount", ["+", "@entity.successCount", 1]],
8000
+ ["set", "@entity.totalCount", ["+", "@entity.totalCount", 1]],
8001
+ ["set", "@entity.lastSuccess", ["time/now"]],
8002
+ ["set", "@entity.errorRate", ["/", "@entity.errorCount", ["math/max", "@entity.totalCount", 1]]]
8003
+ ]
8004
+ },
8005
+ // Closed: record failure, stay closed if under threshold
8006
+ {
8007
+ from: "Closed",
8008
+ to: "Closed",
8009
+ event: "RECORD_FAILURE",
8010
+ guard: ["<", ["+", "@entity.errorCount", 1], "@entity.errorThreshold"],
8011
+ effects: [
8012
+ ["set", "@entity.errorCount", ["+", "@entity.errorCount", 1]],
8013
+ ["set", "@entity.totalCount", ["+", "@entity.totalCount", 1]],
8014
+ ["set", "@entity.lastFailure", ["time/now"]],
8015
+ ["set", "@entity.errorRate", ["/", ["+", "@entity.errorCount", 1], ["math/max", "@entity.totalCount", 1]]]
8016
+ ]
8017
+ },
8018
+ // Closed -> Open: threshold exceeded
8019
+ {
8020
+ from: "Closed",
8021
+ to: "Open",
8022
+ event: "RECORD_FAILURE",
8023
+ guard: [">=", ["+", "@entity.errorCount", 1], "@entity.errorThreshold"],
8024
+ effects: [
8025
+ ["set", "@entity.errorCount", ["+", "@entity.errorCount", 1]],
8026
+ ["set", "@entity.totalCount", ["+", "@entity.totalCount", 1]],
8027
+ ["set", "@entity.lastFailure", ["time/now"]],
8028
+ ["set", "@entity.errorRate", ["/", ["+", "@entity.errorCount", 1], ["math/max", "@entity.totalCount", 1]]],
8029
+ ["emit", "CIRCUIT_OPENED", { errorCount: "@entity.errorCount", errorRate: "@entity.errorRate" }]
8030
+ ]
8031
+ },
8032
+ // Open -> HalfOpen: probe after reset timeout
8033
+ {
8034
+ from: "Open",
8035
+ to: "HalfOpen",
8036
+ event: "PROBE",
8037
+ guard: [">", ["-", ["time/now"], "@entity.lastFailure"], "@entity.resetAfterMs"],
8038
+ effects: [
8039
+ ["set", "@entity.halfOpenAttempts", 0],
8040
+ ["emit", "CIRCUIT_HALF_OPEN", {}]
8041
+ ]
8042
+ },
8043
+ // HalfOpen: success -> close
8044
+ {
8045
+ from: "HalfOpen",
8046
+ to: "Closed",
8047
+ event: "RECORD_SUCCESS",
8048
+ effects: [
8049
+ ["set", "@entity.errorCount", 0],
8050
+ ["set", "@entity.errorRate", 0],
8051
+ ["set", "@entity.halfOpenAttempts", 0],
8052
+ ["set", "@entity.successCount", ["+", "@entity.successCount", 1]],
8053
+ ["set", "@entity.lastSuccess", ["time/now"]],
8054
+ ["emit", "CIRCUIT_CLOSED", {}]
8055
+ ]
8056
+ },
8057
+ // HalfOpen: failure -> back to open
8058
+ {
8059
+ from: "HalfOpen",
8060
+ to: "Open",
8061
+ event: "RECORD_FAILURE",
8062
+ effects: [
8063
+ ["set", "@entity.errorCount", ["+", "@entity.errorCount", 1]],
8064
+ ["set", "@entity.lastFailure", ["time/now"]],
8065
+ ["emit", "CIRCUIT_OPENED", { errorCount: "@entity.errorCount" }]
8066
+ ]
8067
+ },
8068
+ // Reset from any state
8069
+ {
8070
+ from: ["Closed", "Open", "HalfOpen"],
8071
+ to: "Closed",
8072
+ event: "RESET",
8073
+ effects: [
8074
+ ["set", "@entity.errorCount", 0],
8075
+ ["set", "@entity.successCount", 0],
8076
+ ["set", "@entity.totalCount", 0],
8077
+ ["set", "@entity.errorRate", 0],
8078
+ ["set", "@entity.halfOpenAttempts", 0],
8079
+ ["set", "@entity.circuitState", "closed"]
8080
+ ]
8081
+ }
8082
+ ]
8083
+ },
8084
+ ticks: [
8085
+ {
8086
+ name: "probe_half_open",
8087
+ interval: "30000",
8088
+ guard: ["=", "@entity.circuitState", "open"],
8089
+ effects: [["emit", "PROBE"]],
8090
+ description: "Periodically probe to transition from Open to HalfOpen"
8091
+ }
8092
+ ]
7761
8093
  }
7762
- }
7763
- }
7764
- return false;
7765
- });
7766
- }
7767
- function validateBehaviorReference(name) {
7768
- if (!name.startsWith("std-")) {
7769
- return `Behavior name must start with 'std-': ${name}`;
7770
- }
7771
- if (!isKnownBehavior(name)) {
7772
- const suggestions = findSimilarBehaviors(name);
7773
- if (suggestions.length > 0) {
7774
- return `Unknown behavior '${name}'. Did you mean: ${suggestions.join(", ")}?`;
8094
+ ],
8095
+ pages: []
7775
8096
  }
7776
- return `Unknown behavior: ${name}`;
8097
+ ]
8098
+ };
8099
+ var HEALTH_CHECK_BEHAVIOR = {
8100
+ name: "std-health-check",
8101
+ version: "1.0.0",
8102
+ description: "Tick-based health monitoring with degradation detection",
8103
+ orbitals: [
8104
+ {
8105
+ name: "HealthCheckOrbital",
8106
+ entity: {
8107
+ name: "HealthCheckState",
8108
+ persistence: "runtime",
8109
+ fields: [
8110
+ { name: "id", type: "string", required: true },
8111
+ { name: "healthStatus", type: "string", default: "unknown" },
8112
+ { name: "lastCheck", type: "number", default: null },
8113
+ { name: "lastHealthy", type: "number", default: null },
8114
+ { name: "consecutiveFailures", type: "number", default: 0 },
8115
+ { name: "consecutiveSuccesses", type: "number", default: 0 },
8116
+ { name: "checkIntervalMs", type: "number", default: 3e4 },
8117
+ { name: "degradedThreshold", type: "number", default: 2 },
8118
+ { name: "unhealthyThreshold", type: "number", default: 5 },
8119
+ { name: "recoveryThreshold", type: "number", default: 3 },
8120
+ { name: "totalChecks", type: "number", default: 0 },
8121
+ { name: "totalFailures", type: "number", default: 0 }
8122
+ ]
8123
+ },
8124
+ traits: [
8125
+ {
8126
+ name: "HealthCheck",
8127
+ linkedEntity: "HealthCheckState",
8128
+ category: "lifecycle",
8129
+ emits: [
8130
+ { event: "SERVICE_HEALTHY", scope: "external" },
8131
+ { event: "SERVICE_DEGRADED", scope: "external" },
8132
+ { event: "SERVICE_UNHEALTHY", scope: "external" }
8133
+ ],
8134
+ stateMachine: {
8135
+ states: [
8136
+ { name: "Unknown", isInitial: true },
8137
+ { name: "Healthy" },
8138
+ { name: "Degraded" },
8139
+ { name: "Unhealthy" }
8140
+ ],
8141
+ events: [
8142
+ { key: "CHECK_SUCCESS", name: "Check Success" },
8143
+ { key: "CHECK_FAILURE", name: "Check Failure" },
8144
+ { key: "HEALTH_TICK", name: "Health Tick" },
8145
+ { key: "RESET", name: "Reset" }
8146
+ ],
8147
+ transitions: [
8148
+ // Unknown -> Healthy on first success
8149
+ {
8150
+ from: "Unknown",
8151
+ to: "Healthy",
8152
+ event: "CHECK_SUCCESS",
8153
+ effects: [
8154
+ ["set", "@entity.healthStatus", "healthy"],
8155
+ ["set", "@entity.consecutiveSuccesses", 1],
8156
+ ["set", "@entity.consecutiveFailures", 0],
8157
+ ["set", "@entity.lastCheck", ["time/now"]],
8158
+ ["set", "@entity.lastHealthy", ["time/now"]],
8159
+ ["set", "@entity.totalChecks", ["+", "@entity.totalChecks", 1]],
8160
+ ["emit", "SERVICE_HEALTHY", {}]
8161
+ ]
8162
+ },
8163
+ // Unknown -> Degraded on first failure
8164
+ {
8165
+ from: "Unknown",
8166
+ to: "Degraded",
8167
+ event: "CHECK_FAILURE",
8168
+ effects: [
8169
+ ["set", "@entity.healthStatus", "degraded"],
8170
+ ["set", "@entity.consecutiveFailures", 1],
8171
+ ["set", "@entity.consecutiveSuccesses", 0],
8172
+ ["set", "@entity.lastCheck", ["time/now"]],
8173
+ ["set", "@entity.totalChecks", ["+", "@entity.totalChecks", 1]],
8174
+ ["set", "@entity.totalFailures", ["+", "@entity.totalFailures", 1]],
8175
+ ["emit", "SERVICE_DEGRADED", { consecutiveFailures: 1 }]
8176
+ ]
8177
+ },
8178
+ // Healthy: stay healthy on success
8179
+ {
8180
+ from: "Healthy",
8181
+ to: "Healthy",
8182
+ event: "CHECK_SUCCESS",
8183
+ effects: [
8184
+ ["set", "@entity.consecutiveSuccesses", ["+", "@entity.consecutiveSuccesses", 1]],
8185
+ ["set", "@entity.consecutiveFailures", 0],
8186
+ ["set", "@entity.lastCheck", ["time/now"]],
8187
+ ["set", "@entity.lastHealthy", ["time/now"]],
8188
+ ["set", "@entity.totalChecks", ["+", "@entity.totalChecks", 1]]
8189
+ ]
8190
+ },
8191
+ // Healthy -> Degraded on failure
8192
+ {
8193
+ from: "Healthy",
8194
+ to: "Degraded",
8195
+ event: "CHECK_FAILURE",
8196
+ effects: [
8197
+ ["set", "@entity.healthStatus", "degraded"],
8198
+ ["set", "@entity.consecutiveFailures", 1],
8199
+ ["set", "@entity.consecutiveSuccesses", 0],
8200
+ ["set", "@entity.lastCheck", ["time/now"]],
8201
+ ["set", "@entity.totalChecks", ["+", "@entity.totalChecks", 1]],
8202
+ ["set", "@entity.totalFailures", ["+", "@entity.totalFailures", 1]],
8203
+ ["emit", "SERVICE_DEGRADED", { consecutiveFailures: 1 }]
8204
+ ]
8205
+ },
8206
+ // Degraded: stay degraded on failure (below unhealthy threshold)
8207
+ {
8208
+ from: "Degraded",
8209
+ to: "Degraded",
8210
+ event: "CHECK_FAILURE",
8211
+ guard: ["<", ["+", "@entity.consecutiveFailures", 1], "@entity.unhealthyThreshold"],
8212
+ effects: [
8213
+ ["set", "@entity.consecutiveFailures", ["+", "@entity.consecutiveFailures", 1]],
8214
+ ["set", "@entity.consecutiveSuccesses", 0],
8215
+ ["set", "@entity.lastCheck", ["time/now"]],
8216
+ ["set", "@entity.totalChecks", ["+", "@entity.totalChecks", 1]],
8217
+ ["set", "@entity.totalFailures", ["+", "@entity.totalFailures", 1]]
8218
+ ]
8219
+ },
8220
+ // Degraded -> Unhealthy when threshold exceeded
8221
+ {
8222
+ from: "Degraded",
8223
+ to: "Unhealthy",
8224
+ event: "CHECK_FAILURE",
8225
+ guard: [">=", ["+", "@entity.consecutiveFailures", 1], "@entity.unhealthyThreshold"],
8226
+ effects: [
8227
+ ["set", "@entity.healthStatus", "unhealthy"],
8228
+ ["set", "@entity.consecutiveFailures", ["+", "@entity.consecutiveFailures", 1]],
8229
+ ["set", "@entity.lastCheck", ["time/now"]],
8230
+ ["set", "@entity.totalChecks", ["+", "@entity.totalChecks", 1]],
8231
+ ["set", "@entity.totalFailures", ["+", "@entity.totalFailures", 1]],
8232
+ ["emit", "SERVICE_UNHEALTHY", { consecutiveFailures: ["+", "@entity.consecutiveFailures", 1] }]
8233
+ ]
8234
+ },
8235
+ // Degraded -> Healthy on enough successes
8236
+ {
8237
+ from: "Degraded",
8238
+ to: "Healthy",
8239
+ event: "CHECK_SUCCESS",
8240
+ guard: [">=", ["+", "@entity.consecutiveSuccesses", 1], "@entity.recoveryThreshold"],
8241
+ effects: [
8242
+ ["set", "@entity.healthStatus", "healthy"],
8243
+ ["set", "@entity.consecutiveSuccesses", ["+", "@entity.consecutiveSuccesses", 1]],
8244
+ ["set", "@entity.consecutiveFailures", 0],
8245
+ ["set", "@entity.lastCheck", ["time/now"]],
8246
+ ["set", "@entity.lastHealthy", ["time/now"]],
8247
+ ["set", "@entity.totalChecks", ["+", "@entity.totalChecks", 1]],
8248
+ ["emit", "SERVICE_HEALTHY", {}]
8249
+ ]
8250
+ },
8251
+ // Degraded: stay degraded on success (not enough to recover)
8252
+ {
8253
+ from: "Degraded",
8254
+ to: "Degraded",
8255
+ event: "CHECK_SUCCESS",
8256
+ guard: ["<", ["+", "@entity.consecutiveSuccesses", 1], "@entity.recoveryThreshold"],
8257
+ effects: [
8258
+ ["set", "@entity.consecutiveSuccesses", ["+", "@entity.consecutiveSuccesses", 1]],
8259
+ ["set", "@entity.consecutiveFailures", 0],
8260
+ ["set", "@entity.lastCheck", ["time/now"]],
8261
+ ["set", "@entity.totalChecks", ["+", "@entity.totalChecks", 1]]
8262
+ ]
8263
+ },
8264
+ // Unhealthy: stay unhealthy on failure
8265
+ {
8266
+ from: "Unhealthy",
8267
+ to: "Unhealthy",
8268
+ event: "CHECK_FAILURE",
8269
+ effects: [
8270
+ ["set", "@entity.consecutiveFailures", ["+", "@entity.consecutiveFailures", 1]],
8271
+ ["set", "@entity.lastCheck", ["time/now"]],
8272
+ ["set", "@entity.totalChecks", ["+", "@entity.totalChecks", 1]],
8273
+ ["set", "@entity.totalFailures", ["+", "@entity.totalFailures", 1]]
8274
+ ]
8275
+ },
8276
+ // Unhealthy -> Degraded on first success (recovery begins)
8277
+ {
8278
+ from: "Unhealthy",
8279
+ to: "Degraded",
8280
+ event: "CHECK_SUCCESS",
8281
+ effects: [
8282
+ ["set", "@entity.healthStatus", "degraded"],
8283
+ ["set", "@entity.consecutiveSuccesses", 1],
8284
+ ["set", "@entity.consecutiveFailures", 0],
8285
+ ["set", "@entity.lastCheck", ["time/now"]],
8286
+ ["set", "@entity.totalChecks", ["+", "@entity.totalChecks", 1]],
8287
+ ["emit", "SERVICE_DEGRADED", { recovering: true }]
8288
+ ]
8289
+ },
8290
+ // Reset from any state
8291
+ {
8292
+ from: ["Unknown", "Healthy", "Degraded", "Unhealthy"],
8293
+ to: "Unknown",
8294
+ event: "RESET",
8295
+ effects: [
8296
+ ["set", "@entity.healthStatus", "unknown"],
8297
+ ["set", "@entity.consecutiveFailures", 0],
8298
+ ["set", "@entity.consecutiveSuccesses", 0],
8299
+ ["set", "@entity.totalChecks", 0],
8300
+ ["set", "@entity.totalFailures", 0]
8301
+ ]
8302
+ }
8303
+ ]
8304
+ },
8305
+ ticks: [
8306
+ {
8307
+ name: "periodic_health_check",
8308
+ interval: "@entity.checkIntervalMs",
8309
+ effects: [["emit", "HEALTH_TICK"]],
8310
+ description: "Periodically trigger health check"
8311
+ }
8312
+ ]
8313
+ }
8314
+ ],
8315
+ pages: []
8316
+ }
8317
+ ]
8318
+ };
8319
+ var RATE_LIMITER_BEHAVIOR = {
8320
+ name: "std-rate-limiter",
8321
+ version: "1.0.0",
8322
+ description: "Guard-based rate limiting with sliding window reset",
8323
+ orbitals: [
8324
+ {
8325
+ name: "RateLimiterOrbital",
8326
+ entity: {
8327
+ name: "RateLimiterState",
8328
+ persistence: "runtime",
8329
+ fields: [
8330
+ { name: "id", type: "string", required: true },
8331
+ { name: "requestCount", type: "number", default: 0 },
8332
+ { name: "windowStart", type: "number", default: 0 },
8333
+ { name: "rateLimit", type: "number", default: 60 },
8334
+ { name: "windowMs", type: "number", default: 6e4 },
8335
+ { name: "totalRequests", type: "number", default: 0 },
8336
+ { name: "rejectedRequests", type: "number", default: 0 }
8337
+ ]
8338
+ },
8339
+ traits: [
8340
+ {
8341
+ name: "RateLimiter",
8342
+ linkedEntity: "RateLimiterState",
8343
+ category: "lifecycle",
8344
+ emits: [
8345
+ { event: "RATE_LIMIT_EXCEEDED", scope: "external" }
8346
+ ],
8347
+ stateMachine: {
8348
+ states: [
8349
+ { name: "Active", isInitial: true }
8350
+ ],
8351
+ events: [
8352
+ { key: "REQUEST", name: "Record Request" },
8353
+ { key: "REQUEST_REJECTED", name: "Request Rejected" },
8354
+ { key: "WINDOW_RESET", name: "Window Reset" },
8355
+ { key: "RESET", name: "Full Reset" }
8356
+ ],
8357
+ transitions: [
8358
+ // Request allowed
8359
+ {
8360
+ from: "Active",
8361
+ to: "Active",
8362
+ event: "REQUEST",
8363
+ guard: ["<", "@entity.requestCount", "@entity.rateLimit"],
8364
+ effects: [
8365
+ ["set", "@entity.requestCount", ["+", "@entity.requestCount", 1]],
8366
+ ["set", "@entity.totalRequests", ["+", "@entity.totalRequests", 1]]
8367
+ ]
8368
+ },
8369
+ // Request rejected — over limit
8370
+ {
8371
+ from: "Active",
8372
+ to: "Active",
8373
+ event: "REQUEST",
8374
+ guard: [">=", "@entity.requestCount", "@entity.rateLimit"],
8375
+ effects: [
8376
+ ["set", "@entity.rejectedRequests", ["+", "@entity.rejectedRequests", 1]],
8377
+ ["emit", "RATE_LIMIT_EXCEEDED", {
8378
+ requestCount: "@entity.requestCount",
8379
+ rateLimit: "@entity.rateLimit"
8380
+ }]
8381
+ ]
8382
+ },
8383
+ // Sliding window reset
8384
+ {
8385
+ from: "Active",
8386
+ to: "Active",
8387
+ event: "WINDOW_RESET",
8388
+ effects: [
8389
+ ["set", "@entity.requestCount", 0],
8390
+ ["set", "@entity.windowStart", ["time/now"]]
8391
+ ]
8392
+ },
8393
+ // Full counter reset
8394
+ {
8395
+ from: "Active",
8396
+ to: "Active",
8397
+ event: "RESET",
8398
+ effects: [
8399
+ ["set", "@entity.requestCount", 0],
8400
+ ["set", "@entity.totalRequests", 0],
8401
+ ["set", "@entity.rejectedRequests", 0],
8402
+ ["set", "@entity.windowStart", ["time/now"]]
8403
+ ]
8404
+ }
8405
+ ]
8406
+ },
8407
+ ticks: [
8408
+ {
8409
+ name: "window_reset",
8410
+ interval: "@entity.windowMs",
8411
+ effects: [["emit", "WINDOW_RESET"]],
8412
+ description: "Reset request counter on sliding window expiry"
8413
+ }
8414
+ ]
8415
+ }
8416
+ ],
8417
+ pages: []
8418
+ }
8419
+ ]
8420
+ };
8421
+ var CACHE_ASIDE_BEHAVIOR = {
8422
+ name: "std-cache-aside",
8423
+ version: "1.0.0",
8424
+ description: "Cache-aside pattern with TTL-based freshness and eviction",
8425
+ orbitals: [
8426
+ {
8427
+ name: "CacheAsideOrbital",
8428
+ entity: {
8429
+ name: "CacheEntry",
8430
+ persistence: "runtime",
8431
+ fields: [
8432
+ { name: "id", type: "string", required: true },
8433
+ { name: "cacheKey", type: "string", default: "" },
8434
+ { name: "cachedValue", type: "object", default: null },
8435
+ { name: "cachedAt", type: "number", default: 0 },
8436
+ { name: "ttlMs", type: "number", default: 3e5 },
8437
+ { name: "cacheHits", type: "number", default: 0 },
8438
+ { name: "cacheMisses", type: "number", default: 0 },
8439
+ { name: "isFresh", type: "boolean", default: false },
8440
+ { name: "lastAccessed", type: "number", default: 0 }
8441
+ ]
8442
+ },
8443
+ traits: [
8444
+ {
8445
+ name: "CacheAside",
8446
+ linkedEntity: "CacheEntry",
8447
+ category: "lifecycle",
8448
+ emits: [
8449
+ { event: "CACHE_HIT", scope: "internal" },
8450
+ { event: "CACHE_MISS", scope: "internal" },
8451
+ { event: "CACHE_EVICTED", scope: "internal" }
8452
+ ],
8453
+ stateMachine: {
8454
+ states: [
8455
+ { name: "Empty", isInitial: true },
8456
+ { name: "Fresh" },
8457
+ { name: "Stale" }
8458
+ ],
8459
+ events: [
8460
+ { key: "LOOKUP", name: "Cache Lookup" },
8461
+ { key: "POPULATE", name: "Populate Cache" },
8462
+ { key: "INVALIDATE", name: "Invalidate" },
8463
+ { key: "EVICT", name: "Evict" },
8464
+ { key: "EVICTION_TICK", name: "Eviction Tick" }
8465
+ ],
8466
+ transitions: [
8467
+ // Empty: lookup is a miss
8468
+ {
8469
+ from: "Empty",
8470
+ to: "Empty",
8471
+ event: "LOOKUP",
8472
+ effects: [
8473
+ ["set", "@entity.cacheMisses", ["+", "@entity.cacheMisses", 1]],
8474
+ ["set", "@entity.lastAccessed", ["time/now"]],
8475
+ ["emit", "CACHE_MISS", { key: "@entity.cacheKey" }]
8476
+ ]
8477
+ },
8478
+ // Empty → Fresh: populate after fetch
8479
+ {
8480
+ from: "Empty",
8481
+ to: "Fresh",
8482
+ event: "POPULATE",
8483
+ effects: [
8484
+ ["set", "@entity.cachedValue", "@payload.value"],
8485
+ ["set", "@entity.cacheKey", "@payload.key"],
8486
+ ["set", "@entity.cachedAt", ["time/now"]],
8487
+ ["set", "@entity.isFresh", true]
8488
+ ]
8489
+ },
8490
+ // Fresh: lookup is a hit
8491
+ {
8492
+ from: "Fresh",
8493
+ to: "Fresh",
8494
+ event: "LOOKUP",
8495
+ guard: ["<", ["-", ["time/now"], "@entity.cachedAt"], "@entity.ttlMs"],
8496
+ effects: [
8497
+ ["set", "@entity.cacheHits", ["+", "@entity.cacheHits", 1]],
8498
+ ["set", "@entity.lastAccessed", ["time/now"]],
8499
+ ["emit", "CACHE_HIT", { key: "@entity.cacheKey" }]
8500
+ ]
8501
+ },
8502
+ // Fresh → Stale: TTL expired on lookup
8503
+ {
8504
+ from: "Fresh",
8505
+ to: "Stale",
8506
+ event: "LOOKUP",
8507
+ guard: [">=", ["-", ["time/now"], "@entity.cachedAt"], "@entity.ttlMs"],
8508
+ effects: [
8509
+ ["set", "@entity.isFresh", false],
8510
+ ["set", "@entity.cacheMisses", ["+", "@entity.cacheMisses", 1]],
8511
+ ["set", "@entity.lastAccessed", ["time/now"]],
8512
+ ["emit", "CACHE_MISS", { key: "@entity.cacheKey", reason: "ttl_expired" }]
8513
+ ]
8514
+ },
8515
+ // Stale: lookup is a miss
8516
+ {
8517
+ from: "Stale",
8518
+ to: "Stale",
8519
+ event: "LOOKUP",
8520
+ effects: [
8521
+ ["set", "@entity.cacheMisses", ["+", "@entity.cacheMisses", 1]],
8522
+ ["set", "@entity.lastAccessed", ["time/now"]],
8523
+ ["emit", "CACHE_MISS", { key: "@entity.cacheKey", reason: "stale" }]
8524
+ ]
8525
+ },
8526
+ // Stale → Fresh: re-populate
8527
+ {
8528
+ from: "Stale",
8529
+ to: "Fresh",
8530
+ event: "POPULATE",
8531
+ effects: [
8532
+ ["set", "@entity.cachedValue", "@payload.value"],
8533
+ ["set", "@entity.cachedAt", ["time/now"]],
8534
+ ["set", "@entity.isFresh", true]
8535
+ ]
8536
+ },
8537
+ // Fresh → Fresh: update cache
8538
+ {
8539
+ from: "Fresh",
8540
+ to: "Fresh",
8541
+ event: "POPULATE",
8542
+ effects: [
8543
+ ["set", "@entity.cachedValue", "@payload.value"],
8544
+ ["set", "@entity.cachedAt", ["time/now"]]
8545
+ ]
8546
+ },
8547
+ // Invalidate from any cached state
8548
+ {
8549
+ from: ["Fresh", "Stale"],
8550
+ to: "Empty",
8551
+ event: "INVALIDATE",
8552
+ effects: [
8553
+ ["set", "@entity.cachedValue", null],
8554
+ ["set", "@entity.isFresh", false],
8555
+ ["set", "@entity.cachedAt", 0]
8556
+ ]
8557
+ },
8558
+ // Evict (with event)
8559
+ {
8560
+ from: ["Fresh", "Stale"],
8561
+ to: "Empty",
8562
+ event: "EVICT",
8563
+ effects: [
8564
+ ["set", "@entity.cachedValue", null],
8565
+ ["set", "@entity.isFresh", false],
8566
+ ["set", "@entity.cachedAt", 0],
8567
+ ["emit", "CACHE_EVICTED", { key: "@entity.cacheKey" }]
8568
+ ]
8569
+ },
8570
+ // Eviction tick: evict if stale
8571
+ {
8572
+ from: "Stale",
8573
+ to: "Empty",
8574
+ event: "EVICTION_TICK",
8575
+ effects: [
8576
+ ["set", "@entity.cachedValue", null],
8577
+ ["set", "@entity.isFresh", false],
8578
+ ["set", "@entity.cachedAt", 0],
8579
+ ["emit", "CACHE_EVICTED", { key: "@entity.cacheKey", reason: "ttl_eviction" }]
8580
+ ]
8581
+ }
8582
+ ]
8583
+ },
8584
+ ticks: [
8585
+ {
8586
+ name: "eviction_sweep",
8587
+ interval: "60000",
8588
+ guard: ["and", ["!=", "@entity.cachedAt", 0], [">=", ["-", ["time/now"], "@entity.cachedAt"], "@entity.ttlMs"]],
8589
+ effects: [["emit", "EVICTION_TICK"]],
8590
+ description: "Periodically evict stale cache entries"
8591
+ }
8592
+ ]
8593
+ }
8594
+ ],
8595
+ pages: []
8596
+ }
8597
+ ]
8598
+ };
8599
+ var SAGA_BEHAVIOR = {
8600
+ name: "std-saga",
8601
+ version: "1.0.0",
8602
+ description: "Saga pattern with step-by-step execution and reverse compensation on failure",
8603
+ orbitals: [
8604
+ {
8605
+ name: "SagaOrbital",
8606
+ entity: {
8607
+ name: "SagaState",
8608
+ persistence: "runtime",
8609
+ fields: [
8610
+ { name: "id", type: "string", required: true },
8611
+ { name: "sagaName", type: "string", default: "" },
8612
+ { name: "currentStep", type: "number", default: 0 },
8613
+ { name: "totalSteps", type: "number", default: 0 },
8614
+ { name: "sagaStatus", type: "string", default: "idle" },
8615
+ { name: "completedSteps", type: "array", default: [] },
8616
+ { name: "compensatedSteps", type: "array", default: [] },
8617
+ { name: "failedStep", type: "number", default: -1 },
8618
+ { name: "failureReason", type: "string", default: "" },
8619
+ { name: "startedAt", type: "number", default: 0 },
8620
+ { name: "completedAt", type: "number", default: 0 }
8621
+ ]
8622
+ },
8623
+ traits: [
8624
+ {
8625
+ name: "Saga",
8626
+ linkedEntity: "SagaState",
8627
+ category: "lifecycle",
8628
+ emits: [
8629
+ { event: "SAGA_STARTED", scope: "external" },
8630
+ { event: "SAGA_STEP_COMPLETED", scope: "external" },
8631
+ { event: "SAGA_COMPLETED", scope: "external" },
8632
+ { event: "SAGA_COMPENSATING", scope: "external" },
8633
+ { event: "SAGA_COMPENSATION_DONE", scope: "external" },
8634
+ { event: "SAGA_FAILED", scope: "external" }
8635
+ ],
8636
+ stateMachine: {
8637
+ states: [
8638
+ { name: "Idle", isInitial: true },
8639
+ { name: "Running" },
8640
+ { name: "Compensating" },
8641
+ { name: "Completed" },
8642
+ { name: "Failed" }
8643
+ ],
8644
+ events: [
8645
+ { key: "START_SAGA", name: "Start Saga" },
8646
+ { key: "STEP_SUCCESS", name: "Step Success" },
8647
+ { key: "STEP_FAILURE", name: "Step Failure" },
8648
+ { key: "COMPENSATE_SUCCESS", name: "Compensate Success" },
8649
+ { key: "COMPENSATE_FAILURE", name: "Compensate Failure" },
8650
+ { key: "RESET", name: "Reset" }
8651
+ ],
8652
+ transitions: [
8653
+ // Idle → Running: start the saga
8654
+ {
8655
+ from: "Idle",
8656
+ to: "Running",
8657
+ event: "START_SAGA",
8658
+ effects: [
8659
+ ["set", "@entity.sagaStatus", "running"],
8660
+ ["set", "@entity.currentStep", 0],
8661
+ ["set", "@entity.completedSteps", []],
8662
+ ["set", "@entity.compensatedSteps", []],
8663
+ ["set", "@entity.failedStep", -1],
8664
+ ["set", "@entity.failureReason", ""],
8665
+ ["set", "@entity.startedAt", ["time/now"]],
8666
+ ["emit", "SAGA_STARTED", { sagaName: "@entity.sagaName" }]
8667
+ ]
8668
+ },
8669
+ // Running: step success, more steps remaining
8670
+ {
8671
+ from: "Running",
8672
+ to: "Running",
8673
+ event: "STEP_SUCCESS",
8674
+ guard: ["<", ["+", "@entity.currentStep", 1], "@entity.totalSteps"],
8675
+ effects: [
8676
+ ["set", "@entity.currentStep", ["+", "@entity.currentStep", 1]],
8677
+ ["emit", "SAGA_STEP_COMPLETED", {
8678
+ step: "@entity.currentStep",
8679
+ totalSteps: "@entity.totalSteps"
8680
+ }]
8681
+ ]
8682
+ },
8683
+ // Running → Completed: last step succeeded
8684
+ {
8685
+ from: "Running",
8686
+ to: "Completed",
8687
+ event: "STEP_SUCCESS",
8688
+ guard: [">=", ["+", "@entity.currentStep", 1], "@entity.totalSteps"],
8689
+ effects: [
8690
+ ["set", "@entity.sagaStatus", "completed"],
8691
+ ["set", "@entity.completedAt", ["time/now"]],
8692
+ ["emit", "SAGA_COMPLETED", { sagaName: "@entity.sagaName" }]
8693
+ ]
8694
+ },
8695
+ // Running → Compensating: a step failed
8696
+ {
8697
+ from: "Running",
8698
+ to: "Compensating",
8699
+ event: "STEP_FAILURE",
8700
+ effects: [
8701
+ ["set", "@entity.sagaStatus", "compensating"],
8702
+ ["set", "@entity.failedStep", "@entity.currentStep"],
8703
+ ["emit", "SAGA_COMPENSATING", {
8704
+ failedStep: "@entity.currentStep",
8705
+ sagaName: "@entity.sagaName"
8706
+ }]
8707
+ ]
8708
+ },
8709
+ // Compensating: compensation step succeeded, more to undo
8710
+ {
8711
+ from: "Compensating",
8712
+ to: "Compensating",
8713
+ event: "COMPENSATE_SUCCESS",
8714
+ guard: [">", "@entity.currentStep", 0],
8715
+ effects: [
8716
+ ["set", "@entity.currentStep", ["-", "@entity.currentStep", 1]]
8717
+ ]
8718
+ },
8719
+ // Compensating → Failed: all compensations done (reached step 0)
8720
+ {
8721
+ from: "Compensating",
8722
+ to: "Failed",
8723
+ event: "COMPENSATE_SUCCESS",
8724
+ guard: ["<=", "@entity.currentStep", 0],
8725
+ effects: [
8726
+ ["set", "@entity.sagaStatus", "failed"],
8727
+ ["set", "@entity.completedAt", ["time/now"]],
8728
+ ["emit", "SAGA_COMPENSATION_DONE", { sagaName: "@entity.sagaName" }]
8729
+ ]
8730
+ },
8731
+ // Compensating → Failed: compensation itself failed
8732
+ {
8733
+ from: "Compensating",
8734
+ to: "Failed",
8735
+ event: "COMPENSATE_FAILURE",
8736
+ effects: [
8737
+ ["set", "@entity.sagaStatus", "failed"],
8738
+ ["set", "@entity.completedAt", ["time/now"]],
8739
+ ["emit", "SAGA_FAILED", {
8740
+ sagaName: "@entity.sagaName",
8741
+ reason: "Compensation failed"
8742
+ }]
8743
+ ]
8744
+ },
8745
+ // Reset from terminal states
8746
+ {
8747
+ from: ["Completed", "Failed"],
8748
+ to: "Idle",
8749
+ event: "RESET",
8750
+ effects: [
8751
+ ["set", "@entity.sagaStatus", "idle"],
8752
+ ["set", "@entity.currentStep", 0],
8753
+ ["set", "@entity.completedSteps", []],
8754
+ ["set", "@entity.compensatedSteps", []],
8755
+ ["set", "@entity.failedStep", -1],
8756
+ ["set", "@entity.failureReason", ""]
8757
+ ]
8758
+ }
8759
+ ]
8760
+ },
8761
+ ticks: []
8762
+ }
8763
+ ],
8764
+ pages: []
8765
+ }
8766
+ ]
8767
+ };
8768
+ var METRICS_COLLECTOR_BEHAVIOR = {
8769
+ name: "std-metrics-collector",
8770
+ version: "1.0.0",
8771
+ description: "Tick-based metrics aggregation with periodic flush and reporting",
8772
+ orbitals: [
8773
+ {
8774
+ name: "MetricsCollectorOrbital",
8775
+ entity: {
8776
+ name: "MetricsState",
8777
+ persistence: "runtime",
8778
+ fields: [
8779
+ { name: "id", type: "string", required: true },
8780
+ { name: "counters", type: "object", default: {} },
8781
+ { name: "gauges", type: "object", default: {} },
8782
+ { name: "lastFlush", type: "number", default: 0 },
8783
+ { name: "flushIntervalMs", type: "number", default: 6e4 },
8784
+ { name: "totalFlushes", type: "number", default: 0 },
8785
+ { name: "totalRecorded", type: "number", default: 0 }
8786
+ ]
8787
+ },
8788
+ traits: [
8789
+ {
8790
+ name: "MetricsCollector",
8791
+ linkedEntity: "MetricsState",
8792
+ category: "lifecycle",
8793
+ emits: [
8794
+ { event: "METRICS_REPORT", scope: "external" }
8795
+ ],
8796
+ stateMachine: {
8797
+ states: [
8798
+ { name: "Collecting", isInitial: true }
8799
+ ],
8800
+ events: [
8801
+ { key: "RECORD_COUNTER", name: "Record Counter" },
8802
+ { key: "RECORD_GAUGE", name: "Record Gauge" },
8803
+ { key: "FLUSH", name: "Flush Metrics" },
8804
+ { key: "RESET", name: "Reset All" }
8805
+ ],
8806
+ transitions: [
8807
+ // Record a counter increment
8808
+ {
8809
+ from: "Collecting",
8810
+ to: "Collecting",
8811
+ event: "RECORD_COUNTER",
8812
+ effects: [
8813
+ ["set", "@entity.totalRecorded", ["+", "@entity.totalRecorded", 1]]
8814
+ ]
8815
+ },
8816
+ // Record a gauge value
8817
+ {
8818
+ from: "Collecting",
8819
+ to: "Collecting",
8820
+ event: "RECORD_GAUGE",
8821
+ effects: [
8822
+ ["set", "@entity.totalRecorded", ["+", "@entity.totalRecorded", 1]]
8823
+ ]
8824
+ },
8825
+ // Flush: emit report and reset counters
8826
+ {
8827
+ from: "Collecting",
8828
+ to: "Collecting",
8829
+ event: "FLUSH",
8830
+ effects: [
8831
+ ["emit", "METRICS_REPORT", {
8832
+ counters: "@entity.counters",
8833
+ gauges: "@entity.gauges",
8834
+ totalRecorded: "@entity.totalRecorded"
8835
+ }],
8836
+ ["set", "@entity.counters", {}],
8837
+ ["set", "@entity.lastFlush", ["time/now"]],
8838
+ ["set", "@entity.totalFlushes", ["+", "@entity.totalFlushes", 1]]
8839
+ ]
8840
+ },
8841
+ // Full reset
8842
+ {
8843
+ from: "Collecting",
8844
+ to: "Collecting",
8845
+ event: "RESET",
8846
+ effects: [
8847
+ ["set", "@entity.counters", {}],
8848
+ ["set", "@entity.gauges", {}],
8849
+ ["set", "@entity.totalRecorded", 0],
8850
+ ["set", "@entity.totalFlushes", 0],
8851
+ ["set", "@entity.lastFlush", 0]
8852
+ ]
8853
+ }
8854
+ ]
8855
+ },
8856
+ ticks: [
8857
+ {
8858
+ name: "periodic_flush",
8859
+ interval: "@entity.flushIntervalMs",
8860
+ guard: [">", "@entity.totalRecorded", 0],
8861
+ effects: [["emit", "FLUSH"]],
8862
+ description: "Periodically flush accumulated metrics"
8863
+ }
8864
+ ]
8865
+ }
8866
+ ],
8867
+ pages: []
8868
+ }
8869
+ ]
8870
+ };
8871
+ var INFRASTRUCTURE_BEHAVIORS = [
8872
+ CIRCUIT_BREAKER_BEHAVIOR,
8873
+ HEALTH_CHECK_BEHAVIOR,
8874
+ RATE_LIMITER_BEHAVIOR,
8875
+ CACHE_ASIDE_BEHAVIOR,
8876
+ SAGA_BEHAVIOR,
8877
+ METRICS_COLLECTOR_BEHAVIOR
8878
+ ];
8879
+
8880
+ // behaviors/registry.ts
8881
+ var STANDARD_BEHAVIORS = [
8882
+ ...UI_INTERACTION_BEHAVIORS,
8883
+ ...DATA_MANAGEMENT_BEHAVIORS,
8884
+ ...ASYNC_BEHAVIORS,
8885
+ ...FEEDBACK_BEHAVIORS,
8886
+ ...GAME_CORE_BEHAVIORS,
8887
+ ...GAME_ENTITY_BEHAVIORS,
8888
+ ...GAME_UI_BEHAVIORS,
8889
+ ...INFRASTRUCTURE_BEHAVIORS
8890
+ ];
8891
+ var BEHAVIOR_REGISTRY = STANDARD_BEHAVIORS.reduce(
8892
+ (acc, behavior) => {
8893
+ acc[behavior.name] = behavior;
8894
+ return acc;
8895
+ },
8896
+ {}
8897
+ );
8898
+ function getBehavior(name) {
8899
+ return BEHAVIOR_REGISTRY[name];
8900
+ }
8901
+ function isKnownBehavior(name) {
8902
+ return name in BEHAVIOR_REGISTRY;
8903
+ }
8904
+ function getAllBehaviorNames() {
8905
+ return Object.keys(BEHAVIOR_REGISTRY);
8906
+ }
8907
+ function getAllBehaviors() {
8908
+ return STANDARD_BEHAVIORS;
8909
+ }
8910
+ function getAllBehaviorMetadata() {
8911
+ return STANDARD_BEHAVIORS.map(getBehaviorMetadata);
8912
+ }
8913
+ function findBehaviorsForUseCase(useCase) {
8914
+ const lowerUseCase = useCase.toLowerCase();
8915
+ return STANDARD_BEHAVIORS.filter(
8916
+ (behavior) => behavior.description?.toLowerCase().includes(lowerUseCase) ?? false
8917
+ );
8918
+ }
8919
+ function getBehaviorsForEvent(event) {
8920
+ return STANDARD_BEHAVIORS.filter((behavior) => {
8921
+ for (const orbital of behavior.orbitals || []) {
8922
+ for (const trait of orbital.traits || []) {
8923
+ if (typeof trait === "object" && "stateMachine" in trait) {
8924
+ const events = trait.stateMachine?.events || [];
8925
+ if (events.some((e) => e.key === event)) {
8926
+ return true;
8927
+ }
8928
+ }
8929
+ }
8930
+ }
8931
+ return false;
8932
+ });
8933
+ }
8934
+ function getBehaviorsWithState(state) {
8935
+ return STANDARD_BEHAVIORS.filter((behavior) => {
8936
+ for (const orbital of behavior.orbitals || []) {
8937
+ for (const trait of orbital.traits || []) {
8938
+ if (typeof trait === "object" && "stateMachine" in trait) {
8939
+ const states = trait.stateMachine?.states || [];
8940
+ if (states.some((s) => s.name === state)) {
8941
+ return true;
8942
+ }
8943
+ }
8944
+ }
8945
+ }
8946
+ return false;
8947
+ });
8948
+ }
8949
+ function validateBehaviorReference(name) {
8950
+ if (!name.startsWith("std-")) {
8951
+ return `Behavior name must start with 'std-': ${name}`;
8952
+ }
8953
+ if (!isKnownBehavior(name)) {
8954
+ const suggestions = findSimilarBehaviors(name);
8955
+ if (suggestions.length > 0) {
8956
+ return `Unknown behavior '${name}'. Did you mean: ${suggestions.join(", ")}?`;
8957
+ }
8958
+ return `Unknown behavior: ${name}`;
7777
8959
  }
7778
8960
  return null;
7779
8961
  }
@@ -7905,6 +9087,12 @@ var MODULE_DESCRIPTIONS = {
7905
9087
  displayName: "Training Operations",
7906
9088
  description: "Training loops, loss functions, and optimization for neural networks.",
7907
9089
  icon: "\u{1F3AF}"
9090
+ },
9091
+ prob: {
9092
+ name: "Probabilistic",
9093
+ displayName: "Probabilistic Programming",
9094
+ description: "Distribution sampling, Bayesian inference via rejection sampling, and statistical summaries.",
9095
+ icon: "\u{1F3B2}"
7908
9096
  }
7909
9097
  };
7910
9098
  var BEHAVIOR_GROUPINGS = {