@mneme-ai/core 2.19.26 → 2.19.28
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/autonomic_scheduler/autonomic_scheduler.test.d.ts +2 -0
- package/dist/autonomic_scheduler/autonomic_scheduler.test.d.ts.map +1 -0
- package/dist/autonomic_scheduler/autonomic_scheduler.test.js +236 -0
- package/dist/autonomic_scheduler/autonomic_scheduler.test.js.map +1 -0
- package/dist/autonomic_scheduler/index.d.ts +149 -0
- package/dist/autonomic_scheduler/index.d.ts.map +1 -0
- package/dist/autonomic_scheduler/index.js +249 -0
- package/dist/autonomic_scheduler/index.js.map +1 -0
- package/dist/cosmic/aurelian_v1927.test.d.ts +2 -0
- package/dist/cosmic/aurelian_v1927.test.d.ts.map +1 -0
- package/dist/cosmic/aurelian_v1927.test.js +73 -0
- package/dist/cosmic/aurelian_v1927.test.js.map +1 -0
- package/dist/cosmic/aurelian_v1928.test.d.ts +2 -0
- package/dist/cosmic/aurelian_v1928.test.d.ts.map +1 -0
- package/dist/cosmic/aurelian_v1928.test.js +47 -0
- package/dist/cosmic/aurelian_v1928.test.js.map +1 -0
- package/dist/dreamspace_cartographer/dreamspace_cartographer.test.d.ts +2 -0
- package/dist/dreamspace_cartographer/dreamspace_cartographer.test.d.ts.map +1 -0
- package/dist/dreamspace_cartographer/dreamspace_cartographer.test.js +153 -0
- package/dist/dreamspace_cartographer/dreamspace_cartographer.test.js.map +1 -0
- package/dist/dreamspace_cartographer/index.d.ts +110 -0
- package/dist/dreamspace_cartographer/index.d.ts.map +1 -0
- package/dist/dreamspace_cartographer/index.js +175 -0
- package/dist/dreamspace_cartographer/index.js.map +1 -0
- package/dist/dreamspace_federate/dreamspace_federate.test.d.ts +2 -0
- package/dist/dreamspace_federate/dreamspace_federate.test.d.ts.map +1 -0
- package/dist/dreamspace_federate/dreamspace_federate.test.js +199 -0
- package/dist/dreamspace_federate/dreamspace_federate.test.js.map +1 -0
- package/dist/dreamspace_federate/index.d.ts +131 -0
- package/dist/dreamspace_federate/index.d.ts.map +1 -0
- package/dist/dreamspace_federate/index.js +209 -0
- package/dist/dreamspace_federate/index.js.map +1 -0
- package/dist/dreamspace_pair/dreamspace_pair.test.d.ts +2 -0
- package/dist/dreamspace_pair/dreamspace_pair.test.d.ts.map +1 -0
- package/dist/dreamspace_pair/dreamspace_pair.test.js +176 -0
- package/dist/dreamspace_pair/dreamspace_pair.test.js.map +1 -0
- package/dist/dreamspace_pair/index.d.ts +99 -0
- package/dist/dreamspace_pair/index.d.ts.map +1 -0
- package/dist/dreamspace_pair/index.js +161 -0
- package/dist/dreamspace_pair/index.js.map +1 -0
- package/dist/dreamspace_probe/dreamspace_probe.test.d.ts +2 -0
- package/dist/dreamspace_probe/dreamspace_probe.test.d.ts.map +1 -0
- package/dist/dreamspace_probe/dreamspace_probe.test.js +182 -0
- package/dist/dreamspace_probe/dreamspace_probe.test.js.map +1 -0
- package/dist/dreamspace_probe/index.d.ts +125 -0
- package/dist/dreamspace_probe/index.d.ts.map +1 -0
- package/dist/dreamspace_probe/index.js +226 -0
- package/dist/dreamspace_probe/index.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -1
- package/dist/lineage/welcome.d.ts.map +1 -1
- package/dist/lineage/welcome.js +15 -1
- package/dist/lineage/welcome.js.map +1 -1
- package/dist/tribunal/tribunal.d.ts.map +1 -1
- package/dist/tribunal/tribunal.js +29 -2
- package/dist/tribunal/tribunal.js.map +1 -1
- package/dist/tribunal/tribunal.test.js +22 -0
- package/dist/tribunal/tribunal.test.js.map +1 -1
- package/dist/whats_new.d.ts.map +1 -1
- package/dist/whats_new.js +16 -0
- package/dist/whats_new.js.map +1 -1
- package/dist/wrapper_genesis/index.d.ts.map +1 -1
- package/dist/wrapper_genesis/index.js +34 -0
- package/dist/wrapper_genesis/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"autonomic_scheduler.test.d.ts","sourceRoot":"","sources":["../../src/autonomic_scheduler/autonomic_scheduler.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { decideTicks, verifyTickPlan, runTickCycle, verifyCycleReport, computeStats, formatStatsLine, formatPlanLine, freshHealthRecord, DEFAULT_SCHEDULES, } from "./index.js";
|
|
3
|
+
const SECRET = "scheduler-test-secret-997744";
|
|
4
|
+
const MIN = 60_000;
|
|
5
|
+
const HOUR = 60 * MIN;
|
|
6
|
+
function freshHealth() {
|
|
7
|
+
return DEFAULT_SCHEDULES.map((s) => freshHealthRecord(s.organ));
|
|
8
|
+
}
|
|
9
|
+
describe("v2.19.28 SCHEDULER · decideTicks (priority ladder)", () => {
|
|
10
|
+
it("first run: every organ EXCEPT idle-gated should tick (interval_due since 0)", () => {
|
|
11
|
+
const plan = decideTicks({
|
|
12
|
+
health: freshHealth(),
|
|
13
|
+
events: { idleMs: 0 },
|
|
14
|
+
nowMs: 100,
|
|
15
|
+
secret: SECRET,
|
|
16
|
+
});
|
|
17
|
+
const willTick = plan.entries.filter((e) => e.shouldTick).map((e) => e.organ);
|
|
18
|
+
// breath + hormonal (no idle requirement) should fire; sleep + dreamspace need idle.
|
|
19
|
+
expect(willTick).toContain("breath");
|
|
20
|
+
expect(willTick).toContain("hormonal");
|
|
21
|
+
expect(willTick).not.toContain("sleep");
|
|
22
|
+
expect(willTick).not.toContain("dreamspace");
|
|
23
|
+
});
|
|
24
|
+
it("git event fires REFLEX even before interval", () => {
|
|
25
|
+
const health = freshHealth().map((h) => h.organ === "reflex" ? { ...h, lastTickMs: 1000 - 10 } : h);
|
|
26
|
+
const plan = decideTicks({
|
|
27
|
+
health,
|
|
28
|
+
events: { hasGitEvent: true },
|
|
29
|
+
nowMs: 1000,
|
|
30
|
+
secret: SECRET,
|
|
31
|
+
});
|
|
32
|
+
const reflex = plan.entries.find((e) => e.organ === "reflex");
|
|
33
|
+
expect(reflex.shouldTick).toBe(true);
|
|
34
|
+
expect(reflex.reason).toBe("event_triggered");
|
|
35
|
+
});
|
|
36
|
+
it("idle threshold gates SLEEP + DREAMSPACE", () => {
|
|
37
|
+
const plan = decideTicks({
|
|
38
|
+
health: freshHealth(),
|
|
39
|
+
events: { idleMs: 31 * MIN },
|
|
40
|
+
nowMs: 100,
|
|
41
|
+
secret: SECRET,
|
|
42
|
+
});
|
|
43
|
+
const sleep = plan.entries.find((e) => e.organ === "sleep");
|
|
44
|
+
expect(sleep.shouldTick).toBe(true);
|
|
45
|
+
expect(sleep.reason).toBe("idle_threshold");
|
|
46
|
+
});
|
|
47
|
+
it("circuit-breaker open: skip with reason 'circuit_open'", () => {
|
|
48
|
+
const health = freshHealth().map((h) => h.organ === "breath" ? { ...h, cooldownUntilMs: 999_999_999 } : h);
|
|
49
|
+
const plan = decideTicks({
|
|
50
|
+
health,
|
|
51
|
+
events: {},
|
|
52
|
+
nowMs: 1000,
|
|
53
|
+
secret: SECRET,
|
|
54
|
+
});
|
|
55
|
+
const breath = plan.entries.find((e) => e.organ === "breath");
|
|
56
|
+
expect(breath.shouldTick).toBe(false);
|
|
57
|
+
expect(breath.reason).toBe("circuit_open");
|
|
58
|
+
});
|
|
59
|
+
it("HMAC plan signature verifies untampered; rejects tamper", () => {
|
|
60
|
+
const plan = decideTicks({ health: freshHealth(), events: {}, nowMs: 1, secret: SECRET });
|
|
61
|
+
expect(verifyTickPlan(plan, SECRET)).toBe(true);
|
|
62
|
+
expect(verifyTickPlan({ ...plan, decidedAtMs: 999 }, SECRET)).toBe(false);
|
|
63
|
+
});
|
|
64
|
+
it("MEASURED 100% determinism: same input -> same plan sig (30 trials)", () => {
|
|
65
|
+
const input = { health: freshHealth(), events: { idleMs: 100 }, nowMs: 1_000_000, secret: SECRET };
|
|
66
|
+
const firstSig = decideTicks(input).sig;
|
|
67
|
+
let allEqual = true;
|
|
68
|
+
for (let i = 0; i < 30; i++) {
|
|
69
|
+
if (decideTicks(input).sig !== firstSig) {
|
|
70
|
+
allEqual = false;
|
|
71
|
+
break;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
expect(allEqual).toBe(true);
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
describe("v2.19.28 SCHEDULER · runTickCycle (invocation + backoff + fallback)", () => {
|
|
78
|
+
it("happy path: every shouldTick organ invoked + success counted", async () => {
|
|
79
|
+
const invoked = [];
|
|
80
|
+
const invoke = async (organ) => { invoked.push(organ); };
|
|
81
|
+
const r = await runTickCycle({
|
|
82
|
+
health: freshHealth(),
|
|
83
|
+
events: {},
|
|
84
|
+
nowMs: 100,
|
|
85
|
+
invoke,
|
|
86
|
+
secret: SECRET,
|
|
87
|
+
});
|
|
88
|
+
expect(invoked).toContain("breath");
|
|
89
|
+
expect(invoked).toContain("hormonal");
|
|
90
|
+
const successes = r.outcomes.filter((o) => o.ok);
|
|
91
|
+
expect(successes.length).toBeGreaterThan(0);
|
|
92
|
+
});
|
|
93
|
+
it("organ throws: outcome.ok=false, errorMessage captured, never crashes", async () => {
|
|
94
|
+
const invoke = async (organ) => {
|
|
95
|
+
if (organ === "breath")
|
|
96
|
+
throw new Error("boom");
|
|
97
|
+
};
|
|
98
|
+
const r = await runTickCycle({
|
|
99
|
+
health: freshHealth(),
|
|
100
|
+
events: {},
|
|
101
|
+
nowMs: 100,
|
|
102
|
+
invoke,
|
|
103
|
+
secret: SECRET,
|
|
104
|
+
});
|
|
105
|
+
const breath = r.outcomes.find((o) => o.organ === "breath");
|
|
106
|
+
expect(breath.ok).toBe(false);
|
|
107
|
+
expect(breath.errorMessage).toBe("boom");
|
|
108
|
+
});
|
|
109
|
+
it("circuit-breaker: 3 consecutive failures opens 1hr cooldown", async () => {
|
|
110
|
+
let health = freshHealth();
|
|
111
|
+
const invoke = async () => { throw new Error("always fail"); };
|
|
112
|
+
let lastCycleNow = 100;
|
|
113
|
+
for (let i = 0; i < 3; i++) {
|
|
114
|
+
lastCycleNow = 100 + i * 100 * MIN;
|
|
115
|
+
const r = await runTickCycle({
|
|
116
|
+
health, events: {}, nowMs: lastCycleNow, invoke, secret: SECRET,
|
|
117
|
+
});
|
|
118
|
+
health = r.newHealth;
|
|
119
|
+
}
|
|
120
|
+
const breath = health.find((h) => h.organ === "breath");
|
|
121
|
+
expect(breath.consecutiveFailures).toBeGreaterThanOrEqual(3);
|
|
122
|
+
// cooldown is set to lastCycleNow + 1hr; verify ~1hr from last tick.
|
|
123
|
+
expect(breath.cooldownUntilMs).toBeGreaterThan(lastCycleNow);
|
|
124
|
+
expect(breath.cooldownUntilMs - lastCycleNow).toBeCloseTo(HOUR, -3);
|
|
125
|
+
});
|
|
126
|
+
it("success after failure RESETS consecutiveFailures + closes cooldown", async () => {
|
|
127
|
+
let health = freshHealth().map((h) => h.organ === "breath" ? { ...h, consecutiveFailures: 2, cooldownUntilMs: 500 } : h);
|
|
128
|
+
const invoke = async () => { };
|
|
129
|
+
const r = await runTickCycle({
|
|
130
|
+
health, events: {}, nowMs: 1_000_000, invoke, secret: SECRET,
|
|
131
|
+
});
|
|
132
|
+
const breath = r.newHealth.find((h) => h.organ === "breath");
|
|
133
|
+
expect(breath.consecutiveFailures).toBe(0);
|
|
134
|
+
expect(breath.cooldownUntilMs).toBe(0);
|
|
135
|
+
});
|
|
136
|
+
it("HMAC cycle report sig verifies; rejects tamper", async () => {
|
|
137
|
+
const r = await runTickCycle({
|
|
138
|
+
health: freshHealth(), events: {}, nowMs: 100,
|
|
139
|
+
invoke: async () => { }, secret: SECRET,
|
|
140
|
+
});
|
|
141
|
+
expect(verifyCycleReport(r, SECRET)).toBe(true);
|
|
142
|
+
expect(verifyCycleReport({ ...r, startedAtMs: 999 }, SECRET)).toBe(false);
|
|
143
|
+
});
|
|
144
|
+
it("MEASURED 24/7 resilience: 100 consecutive cycles with random failures never crashes", async () => {
|
|
145
|
+
let health = freshHealth();
|
|
146
|
+
const invoke = async () => {
|
|
147
|
+
if (Math.random() < 0.3)
|
|
148
|
+
throw new Error("random");
|
|
149
|
+
};
|
|
150
|
+
let nowMs = 100;
|
|
151
|
+
let crashed = false;
|
|
152
|
+
try {
|
|
153
|
+
for (let i = 0; i < 100; i++) {
|
|
154
|
+
const r = await runTickCycle({
|
|
155
|
+
health, events: { idleMs: 60 * MIN }, nowMs, invoke, secret: SECRET,
|
|
156
|
+
});
|
|
157
|
+
health = r.newHealth;
|
|
158
|
+
nowMs += 2 * MIN;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
catch {
|
|
162
|
+
crashed = true;
|
|
163
|
+
}
|
|
164
|
+
expect(crashed).toBe(false);
|
|
165
|
+
});
|
|
166
|
+
});
|
|
167
|
+
describe("v2.19.28 SCHEDULER · stats + formatter", () => {
|
|
168
|
+
it("computeStats: totals + successRate + healthy/cooldown counts", () => {
|
|
169
|
+
const health = [
|
|
170
|
+
{ organ: "breath", lastTickMs: 0, lastSuccessMs: 0, consecutiveFailures: 0, cooldownUntilMs: 0, totalTicks: 10, totalSuccesses: 9, totalFailures: 1 },
|
|
171
|
+
{ organ: "reflex", lastTickMs: 0, lastSuccessMs: 0, consecutiveFailures: 5, cooldownUntilMs: 999_999_999, totalTicks: 8, totalSuccesses: 0, totalFailures: 8 },
|
|
172
|
+
];
|
|
173
|
+
const s = computeStats(health, 1000);
|
|
174
|
+
expect(s.totalOrgans).toBe(2);
|
|
175
|
+
expect(s.totalTicks).toBe(18);
|
|
176
|
+
expect(s.totalSuccesses).toBe(9);
|
|
177
|
+
expect(s.successRate).toBeCloseTo(0.5, 3);
|
|
178
|
+
expect(s.organsInCooldown).toBe(1);
|
|
179
|
+
expect(s.organsHealthy).toBe(1);
|
|
180
|
+
});
|
|
181
|
+
it("formatStatsLine includes all health metrics", () => {
|
|
182
|
+
const s = computeStats([{ organ: "breath", lastTickMs: 0, lastSuccessMs: 0, consecutiveFailures: 0, cooldownUntilMs: 0, totalTicks: 5, totalSuccesses: 5, totalFailures: 0 }], 1000);
|
|
183
|
+
const line = formatStatsLine(s);
|
|
184
|
+
expect(line).toContain("SCHEDULER");
|
|
185
|
+
expect(line).toContain("100.0%");
|
|
186
|
+
});
|
|
187
|
+
it("formatPlanLine summarises will/skip", () => {
|
|
188
|
+
const plan = decideTicks({ health: freshHealth(), events: {}, nowMs: 1, secret: SECRET });
|
|
189
|
+
const line = formatPlanLine(plan);
|
|
190
|
+
expect(line).toContain("PLAN");
|
|
191
|
+
});
|
|
192
|
+
});
|
|
193
|
+
describe("v2.19.28 SCHEDULER · 24/7 invariants (always-active by design)", () => {
|
|
194
|
+
it("never throws even with empty health + empty schedule + empty events", () => {
|
|
195
|
+
expect(() => decideTicks({ schedules: [], health: [], events: {}, nowMs: 0, secret: SECRET })).not.toThrow();
|
|
196
|
+
});
|
|
197
|
+
it("decideTicks always produces an entry per schedule (no silent drops)", () => {
|
|
198
|
+
const plan = decideTicks({ health: freshHealth(), events: {}, nowMs: 100, secret: SECRET });
|
|
199
|
+
expect(plan.entries.length).toBe(DEFAULT_SCHEDULES.length);
|
|
200
|
+
});
|
|
201
|
+
it("MEASURED 100% determinism on health record initialization (50 fresh records)", () => {
|
|
202
|
+
const firstStr = JSON.stringify(freshHealthRecord("breath"));
|
|
203
|
+
for (let i = 0; i < 50; i++) {
|
|
204
|
+
expect(JSON.stringify(freshHealthRecord("breath"))).toBe(firstStr);
|
|
205
|
+
}
|
|
206
|
+
});
|
|
207
|
+
});
|
|
208
|
+
describe("v2.19.28 SCHEDULER · B1 root-cause regression (organs MUST tick on schedule)", () => {
|
|
209
|
+
it("B1 fix proof: after 1 cycle, .breath health record shows lastTickMs > 0 + totalTicks > 0", async () => {
|
|
210
|
+
const invoke = async () => { };
|
|
211
|
+
const r = await runTickCycle({
|
|
212
|
+
health: freshHealth(), events: {}, nowMs: 1_000_000,
|
|
213
|
+
invoke, secret: SECRET,
|
|
214
|
+
});
|
|
215
|
+
const breath = r.newHealth.find((h) => h.organ === "breath");
|
|
216
|
+
expect(breath.lastTickMs).toBeGreaterThan(0);
|
|
217
|
+
expect(breath.totalTicks).toBeGreaterThan(0);
|
|
218
|
+
expect(breath.totalSuccesses).toBeGreaterThan(0);
|
|
219
|
+
});
|
|
220
|
+
it("after 24 simulated cycles (representing 24min real time at 60s heartbeat), breath ticked >=24 times", async () => {
|
|
221
|
+
let health = freshHealth();
|
|
222
|
+
let nowMs = 1_000_000;
|
|
223
|
+
for (let i = 0; i < 24; i++) {
|
|
224
|
+
const r = await runTickCycle({
|
|
225
|
+
health, events: {}, nowMs,
|
|
226
|
+
invoke: async () => { }, secret: SECRET,
|
|
227
|
+
});
|
|
228
|
+
health = r.newHealth;
|
|
229
|
+
nowMs += 65 * 1000; // slightly more than 60s interval
|
|
230
|
+
}
|
|
231
|
+
const breath = health.find((h) => h.organ === "breath");
|
|
232
|
+
expect(breath.totalTicks).toBe(24);
|
|
233
|
+
expect(breath.totalSuccesses).toBe(24);
|
|
234
|
+
});
|
|
235
|
+
});
|
|
236
|
+
//# sourceMappingURL=autonomic_scheduler.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"autonomic_scheduler.test.js","sourceRoot":"","sources":["../../src/autonomic_scheduler/autonomic_scheduler.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EACL,WAAW,EACX,cAAc,EACd,YAAY,EACZ,iBAAiB,EACjB,YAAY,EACZ,eAAe,EACf,cAAc,EACd,iBAAiB,EACjB,iBAAiB,GAIlB,MAAM,YAAY,CAAC;AAEpB,MAAM,MAAM,GAAG,8BAA8B,CAAC;AAC9C,MAAM,GAAG,GAAG,MAAM,CAAC;AACnB,MAAM,IAAI,GAAG,EAAE,GAAG,GAAG,CAAC;AAEtB,SAAS,WAAW;IAClB,OAAO,iBAAiB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;AAClE,CAAC;AAED,QAAQ,CAAC,oDAAoD,EAAE,GAAG,EAAE;IAClE,EAAE,CAAC,6EAA6E,EAAE,GAAG,EAAE;QACrF,MAAM,IAAI,GAAG,WAAW,CAAC;YACvB,MAAM,EAAE,WAAW,EAAE;YACrB,MAAM,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE;YACrB,KAAK,EAAE,GAAG;YACV,MAAM,EAAE,MAAM;SACf,CAAC,CAAC;QACH,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;QAC9E,qFAAqF;QACrF,MAAM,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC,QAAqB,CAAC,CAAC;QAClD,MAAM,CAAC,QAAQ,CAAC,CAAC,SAAS,CAAC,UAAuB,CAAC,CAAC;QACpD,MAAM,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,OAAoB,CAAC,CAAC;QACrD,MAAM,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,YAAyB,CAAC,CAAC;IAC5D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6CAA6C,EAAE,GAAG,EAAE;QACrD,MAAM,MAAM,GAAG,WAAW,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CACrC,CAAC,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,UAAU,EAAE,IAAI,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAC3D,CAAC;QACF,MAAM,IAAI,GAAG,WAAW,CAAC;YACvB,MAAM;YACN,MAAM,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE;YAC7B,KAAK,EAAE,IAAI;YACX,MAAM,EAAE,MAAM;SACf,CAAC,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,QAAQ,CAAE,CAAC;QAC/D,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACrC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;IAChD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yCAAyC,EAAE,GAAG,EAAE;QACjD,MAAM,IAAI,GAAG,WAAW,CAAC;YACvB,MAAM,EAAE,WAAW,EAAE;YACrB,MAAM,EAAE,EAAE,MAAM,EAAE,EAAE,GAAG,GAAG,EAAE;YAC5B,KAAK,EAAE,GAAG;YACV,MAAM,EAAE,MAAM;SACf,CAAC,CAAC;QACH,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,OAAO,CAAE,CAAC;QAC7D,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACpC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;IAC9C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,uDAAuD,EAAE,GAAG,EAAE;QAC/D,MAAM,MAAM,GAAG,WAAW,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CACrC,CAAC,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,eAAe,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC,CAAC,CAClE,CAAC;QACF,MAAM,IAAI,GAAG,WAAW,CAAC;YACvB,MAAM;YACN,MAAM,EAAE,EAAE;YACV,KAAK,EAAE,IAAI;YACX,MAAM,EAAE,MAAM;SACf,CAAC,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,QAAQ,CAAE,CAAC;QAC/D,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACtC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;IAC7C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yDAAyD,EAAE,GAAG,EAAE;QACjE,MAAM,IAAI,GAAG,WAAW,CAAC,EAAE,MAAM,EAAE,WAAW,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;QAC1F,MAAM,CAAC,cAAc,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAChD,MAAM,CAAC,cAAc,CAAC,EAAE,GAAG,IAAI,EAAE,WAAW,EAAE,GAAG,EAAE,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC5E,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oEAAoE,EAAE,GAAG,EAAE;QAC5E,MAAM,KAAK,GAAG,EAAE,MAAM,EAAE,WAAW,EAAE,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC;QACnG,MAAM,QAAQ,GAAG,WAAW,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC;QACxC,IAAI,QAAQ,GAAG,IAAI,CAAC;QACpB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC;YAC5B,IAAI,WAAW,CAAC,KAAK,CAAC,CAAC,GAAG,KAAK,QAAQ,EAAE,CAAC;gBAAC,QAAQ,GAAG,KAAK,CAAC;gBAAC,MAAM;YAAC,CAAC;QACvE,CAAC;QACD,MAAM,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC9B,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,qEAAqE,EAAE,GAAG,EAAE;IACnF,EAAE,CAAC,8DAA8D,EAAE,KAAK,IAAI,EAAE;QAC5E,MAAM,OAAO,GAAgB,EAAE,CAAC;QAChC,MAAM,MAAM,GAAG,KAAK,EAAE,KAAgB,EAAE,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QACpE,MAAM,CAAC,GAAG,MAAM,YAAY,CAAC;YAC3B,MAAM,EAAE,WAAW,EAAE;YACrB,MAAM,EAAE,EAAE;YACV,KAAK,EAAE,GAAG;YACV,MAAM;YACN,MAAM,EAAE,MAAM;SACf,CAAC,CAAC;QACH,MAAM,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,QAAqB,CAAC,CAAC;QACjD,MAAM,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,UAAuB,CAAC,CAAC;QACnD,MAAM,SAAS,GAAG,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QACjD,MAAM,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;IAC9C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sEAAsE,EAAE,KAAK,IAAI,EAAE;QACpF,MAAM,MAAM,GAAG,KAAK,EAAE,KAAgB,EAAE,EAAE;YACxC,IAAI,KAAK,KAAK,QAAQ;gBAAE,MAAM,IAAI,KAAK,CAAC,MAAM,CAAC,CAAC;QAClD,CAAC,CAAC;QACF,MAAM,CAAC,GAAG,MAAM,YAAY,CAAC;YAC3B,MAAM,EAAE,WAAW,EAAE;YACrB,MAAM,EAAE,EAAE;YACV,KAAK,EAAE,GAAG;YACV,MAAM;YACN,MAAM,EAAE,MAAM;SACf,CAAC,CAAC;QACH,MAAM,MAAM,GAAG,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,QAAQ,CAAE,CAAC;QAC7D,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC9B,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAC3C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4DAA4D,EAAE,KAAK,IAAI,EAAE;QAC1E,IAAI,MAAM,GAAG,WAAW,EAAE,CAAC;QAC3B,MAAM,MAAM,GAAG,KAAK,IAAI,EAAE,GAAG,MAAM,IAAI,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC;QAC/D,IAAI,YAAY,GAAG,GAAG,CAAC;QACvB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YAC3B,YAAY,GAAG,GAAG,GAAG,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC;YACnC,MAAM,CAAC,GAAG,MAAM,YAAY,CAAC;gBAC3B,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,KAAK,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;aAChE,CAAC,CAAC;YACH,MAAM,GAAG,CAAC,CAAC,SAAS,CAAC;QACvB,CAAC;QACD,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,QAAQ,CAAE,CAAC;QACzD,MAAM,CAAC,MAAM,CAAC,mBAAmB,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAC,CAAC;QAC7D,qEAAqE;QACrE,MAAM,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,eAAe,CAAC,YAAY,CAAC,CAAC;QAC7D,MAAM,CAAC,MAAM,CAAC,eAAe,GAAG,YAAY,CAAC,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IACtE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oEAAoE,EAAE,KAAK,IAAI,EAAE;QAClF,IAAI,MAAM,GAAG,WAAW,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CACnC,CAAC,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,mBAAmB,EAAE,CAAC,EAAE,eAAe,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAClF,CAAC;QACF,MAAM,MAAM,GAAG,KAAK,IAAI,EAAE,GAAY,CAAC,CAAC;QACxC,MAAM,CAAC,GAAG,MAAM,YAAY,CAAC;YAC3B,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;SAC7D,CAAC,CAAC;QACH,MAAM,MAAM,GAAG,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,QAAQ,CAAE,CAAC;QAC9D,MAAM,CAAC,MAAM,CAAC,mBAAmB,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC3C,MAAM,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACzC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gDAAgD,EAAE,KAAK,IAAI,EAAE;QAC9D,MAAM,CAAC,GAAG,MAAM,YAAY,CAAC;YAC3B,MAAM,EAAE,WAAW,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,KAAK,EAAE,GAAG;YAC7C,MAAM,EAAE,KAAK,IAAI,EAAE,GAAE,CAAC,EAAE,MAAM,EAAE,MAAM;SACvC,CAAC,CAAC;QACH,MAAM,CAAC,iBAAiB,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAChD,MAAM,CAAC,iBAAiB,CAAC,EAAE,GAAG,CAAC,EAAE,WAAW,EAAE,GAAG,EAAE,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC5E,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qFAAqF,EAAE,KAAK,IAAI,EAAE;QACnG,IAAI,MAAM,GAAG,WAAW,EAAE,CAAC;QAC3B,MAAM,MAAM,GAAG,KAAK,IAAI,EAAE;YACxB,IAAI,IAAI,CAAC,MAAM,EAAE,GAAG,GAAG;gBAAE,MAAM,IAAI,KAAK,CAAC,QAAQ,CAAC,CAAC;QACrD,CAAC,CAAC;QACF,IAAI,KAAK,GAAG,GAAG,CAAC;QAChB,IAAI,OAAO,GAAG,KAAK,CAAC;QACpB,IAAI,CAAC;YACH,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;gBAC7B,MAAM,CAAC,GAAG,MAAM,YAAY,CAAC;oBAC3B,MAAM,EAAE,MAAM,EAAE,EAAE,MAAM,EAAE,EAAE,GAAG,GAAG,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;iBACpE,CAAC,CAAC;gBACH,MAAM,GAAG,CAAC,CAAC,SAAS,CAAC;gBACrB,KAAK,IAAI,CAAC,GAAG,GAAG,CAAC;YACnB,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,GAAG,IAAI,CAAC;QACjB,CAAC;QACD,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC9B,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,wCAAwC,EAAE,GAAG,EAAE;IACtD,EAAE,CAAC,8DAA8D,EAAE,GAAG,EAAE;QACtE,MAAM,MAAM,GAAwB;YAClC,EAAE,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,CAAC,EAAE,aAAa,EAAE,CAAC,EAAE,mBAAmB,EAAE,CAAC,EAAE,eAAe,EAAE,CAAC,EAAE,UAAU,EAAE,EAAE,EAAE,cAAc,EAAE,CAAC,EAAE,aAAa,EAAE,CAAC,EAAE;YACrJ,EAAE,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,CAAC,EAAE,aAAa,EAAE,CAAC,EAAE,mBAAmB,EAAE,CAAC,EAAE,eAAe,EAAE,WAAW,EAAE,UAAU,EAAE,CAAC,EAAE,cAAc,EAAE,CAAC,EAAE,aAAa,EAAE,CAAC,EAAE;SAC/J,CAAC;QACF,MAAM,CAAC,GAAG,YAAY,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QACrC,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC9B,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAC9B,MAAM,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACjC,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,WAAW,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QAC1C,MAAM,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACnC,MAAM,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6CAA6C,EAAE,GAAG,EAAE;QACrD,MAAM,CAAC,GAAG,YAAY,CAAC,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,CAAC,EAAE,aAAa,EAAE,CAAC,EAAE,mBAAmB,EAAE,CAAC,EAAE,eAAe,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,cAAc,EAAE,CAAC,EAAE,aAAa,EAAE,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,CAAC;QACrL,MAAM,IAAI,GAAG,eAAe,CAAC,CAAC,CAAC,CAAC;QAChC,MAAM,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC;QACpC,MAAM,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;IACnC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qCAAqC,EAAE,GAAG,EAAE;QAC7C,MAAM,IAAI,GAAG,WAAW,CAAC,EAAE,MAAM,EAAE,WAAW,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;QAC1F,MAAM,IAAI,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC;QAClC,MAAM,CAAC,IAAI,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IACjC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,gEAAgE,EAAE,GAAG,EAAE;IAC9E,EAAE,CAAC,qEAAqE,EAAE,GAAG,EAAE;QAC7E,MAAM,CAAC,GAAG,EAAE,CAAC,WAAW,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC;IAC/G,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qEAAqE,EAAE,GAAG,EAAE;QAC7E,MAAM,IAAI,GAAG,WAAW,CAAC,EAAE,MAAM,EAAE,WAAW,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;QAC5F,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,iBAAiB,CAAC,MAAM,CAAC,CAAC;IAC7D,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8EAA8E,EAAE,GAAG,EAAE;QACtF,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,iBAAiB,CAAC,QAAQ,CAAC,CAAC,CAAC;QAC7D,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC;YAC5B,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,iBAAiB,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACrE,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,8EAA8E,EAAE,GAAG,EAAE;IAC5F,EAAE,CAAC,0FAA0F,EAAE,KAAK,IAAI,EAAE;QACxG,MAAM,MAAM,GAAG,KAAK,IAAI,EAAE,GAAE,CAAC,CAAC;QAC9B,MAAM,CAAC,GAAG,MAAM,YAAY,CAAC;YAC3B,MAAM,EAAE,WAAW,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,KAAK,EAAE,SAAS;YACnD,MAAM,EAAE,MAAM,EAAE,MAAM;SACvB,CAAC,CAAC;QACH,MAAM,MAAM,GAAG,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,QAAQ,CAAE,CAAC;QAC9D,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;QAC7C,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;QAC7C,MAAM,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;IACnD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qGAAqG,EAAE,KAAK,IAAI,EAAE;QACnH,IAAI,MAAM,GAAG,WAAW,EAAE,CAAC;QAC3B,IAAI,KAAK,GAAG,SAAS,CAAC;QACtB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC;YAC5B,MAAM,CAAC,GAAG,MAAM,YAAY,CAAC;gBAC3B,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,KAAK;gBACzB,MAAM,EAAE,KAAK,IAAI,EAAE,GAAE,CAAC,EAAE,MAAM,EAAE,MAAM;aACvC,CAAC,CAAC;YACH,MAAM,GAAG,CAAC,CAAC,SAAS,CAAC;YACrB,KAAK,IAAI,EAAE,GAAG,IAAI,CAAC,CAAC,kCAAkC;QACxD,CAAC;QACD,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,KAAK,QAAQ,CAAE,CAAC;QACzD,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACnC,MAAM,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACzC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* v2.19.28 — MNEME AUTONOMIC SCHEDULER (ROOT-CAUSE FIX for dormant LIMBIC + DREAMSPACE)
|
|
3
|
+
*
|
|
4
|
+
* "daemon ทำงาน แต่ daemon ไม่ 'เรียก' LIMBIC organs อัตโนมัติ"
|
|
5
|
+
* — user audit, 2026-05-17
|
|
6
|
+
*
|
|
7
|
+
* Diagnosis: every prior release shipped organs as MCP tools and trusted
|
|
8
|
+
* that "some AI agent will call them". Reality:
|
|
9
|
+
* - AI agents don't know WHEN to call (e.g., "every 60s")
|
|
10
|
+
* - Daemon was alive but ticked only legacy (nucleus / oracle / pheromones)
|
|
11
|
+
* - .mneme/breath / .mneme/reflex / .mneme/sleep never got written
|
|
12
|
+
* - 49 organ tools = 0 invocations in practice
|
|
13
|
+
*
|
|
14
|
+
* AUTONOMIC SCHEDULER fixes ONE bug at the root: introduce a tick planner
|
|
15
|
+
* that runs every daemon heartbeat, decides which organs should fire NOW,
|
|
16
|
+
* then invokes them with per-organ backoff + fallback + circuit-breaker.
|
|
17
|
+
*
|
|
18
|
+
* 5 named schedules (each independently configurable):
|
|
19
|
+
* - BREATH every 60s (heartbeat; respawn if dead)
|
|
20
|
+
* - REFLEX on every git_event / file_save (debounced by minIntervalMs)
|
|
21
|
+
* - SLEEP every 30min during idle (consolidation cycle)
|
|
22
|
+
* - DREAMSPACE every 60min during idle (probe + cartographer cycle)
|
|
23
|
+
* - HORMONAL every 5min OR on observable event (mood update)
|
|
24
|
+
*
|
|
25
|
+
* Composes onto:
|
|
26
|
+
* - v2.19.23 BREATH (heartbeat target)
|
|
27
|
+
* - v2.19.22 REFLEX (observe + prefetch target)
|
|
28
|
+
* - v2.19.25 SLEEP TRAINING (cycle target)
|
|
29
|
+
* - v2.19.26 + 27 DREAMSPACE (probe + cartographer target)
|
|
30
|
+
* - v2.19.23 + 25 HORMONAL + ENDOCRINE (update target)
|
|
31
|
+
* - v2.19.23 THALAMUS (tier routing)
|
|
32
|
+
*
|
|
33
|
+
* Honest scope:
|
|
34
|
+
* - PURE FUNCTION decideTicks; caller (daemon) wires the actual invoker.
|
|
35
|
+
* - Per-organ circuit-breaker: 3 consecutive failures = 1hr cooldown.
|
|
36
|
+
* - Exception-handled at every level (white loop never crashes).
|
|
37
|
+
* - HMAC-chained ScheduleLedger so post-hoc audit catches missed ticks.
|
|
38
|
+
* - 24/7 always-active by design — fallback to "skipped" record on failure.
|
|
39
|
+
*/
|
|
40
|
+
declare const PROTOCOL_VERSION: 1;
|
|
41
|
+
export type OrganKind = "breath" | "reflex" | "sleep" | "dreamspace" | "hormonal";
|
|
42
|
+
export type TickReason = "interval_due" | "event_triggered" | "idle_threshold" | "manual" | "cooldown_active" | "circuit_open";
|
|
43
|
+
export interface OrganSchedule {
|
|
44
|
+
organ: OrganKind;
|
|
45
|
+
/** Minimum ms between automatic ticks. */
|
|
46
|
+
intervalMs: number;
|
|
47
|
+
/** If true, also fire on caller-supplied event signal (e.g., git_commit). */
|
|
48
|
+
fireOnEvent?: boolean;
|
|
49
|
+
/** Require idleMs > this to consider firing (0 = no idle requirement). */
|
|
50
|
+
requireIdleMs?: number;
|
|
51
|
+
}
|
|
52
|
+
export declare const DEFAULT_SCHEDULES: readonly OrganSchedule[];
|
|
53
|
+
export interface OrganHealthRecord {
|
|
54
|
+
organ: OrganKind;
|
|
55
|
+
lastTickMs: number;
|
|
56
|
+
lastSuccessMs: number;
|
|
57
|
+
consecutiveFailures: number;
|
|
58
|
+
cooldownUntilMs: number;
|
|
59
|
+
totalTicks: number;
|
|
60
|
+
totalSuccesses: number;
|
|
61
|
+
totalFailures: number;
|
|
62
|
+
}
|
|
63
|
+
export declare function freshHealthRecord(organ: OrganKind): OrganHealthRecord;
|
|
64
|
+
export interface TickPlanEntry {
|
|
65
|
+
organ: OrganKind;
|
|
66
|
+
shouldTick: boolean;
|
|
67
|
+
reason: TickReason;
|
|
68
|
+
details: string;
|
|
69
|
+
}
|
|
70
|
+
export interface TickPlan {
|
|
71
|
+
v: typeof PROTOCOL_VERSION;
|
|
72
|
+
decidedAtMs: number;
|
|
73
|
+
entries: TickPlanEntry[];
|
|
74
|
+
sig: string;
|
|
75
|
+
}
|
|
76
|
+
export interface EventSignals {
|
|
77
|
+
/** Recent git activity (commit / push) since last tick. */
|
|
78
|
+
hasGitEvent?: boolean;
|
|
79
|
+
/** Recent file_save activity since last tick. */
|
|
80
|
+
hasFileSaveEvent?: boolean;
|
|
81
|
+
/** Idle ms since last user activity. */
|
|
82
|
+
idleMs?: number;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Pure decision: which organs should tick RIGHT NOW given health records +
|
|
86
|
+
* schedules + event signals + wall-clock time?
|
|
87
|
+
*
|
|
88
|
+
* Priority order per organ:
|
|
89
|
+
* 1. cooldownUntilMs > now → skip (circuit_open)
|
|
90
|
+
* 2. fireOnEvent + event present → tick (event_triggered)
|
|
91
|
+
* 3. now - lastTickMs >= interval AND idle requirement met → tick (interval_due / idle_threshold)
|
|
92
|
+
* 4. else → skip (no_reason)
|
|
93
|
+
*/
|
|
94
|
+
export declare function decideTicks(input: {
|
|
95
|
+
schedules?: readonly OrganSchedule[];
|
|
96
|
+
health: OrganHealthRecord[];
|
|
97
|
+
events: EventSignals;
|
|
98
|
+
nowMs: number;
|
|
99
|
+
secret?: string;
|
|
100
|
+
}): TickPlan;
|
|
101
|
+
export declare function verifyTickPlan(p: TickPlan, secret?: string): boolean;
|
|
102
|
+
export interface TickOutcome {
|
|
103
|
+
organ: OrganKind;
|
|
104
|
+
shouldTick: boolean;
|
|
105
|
+
reason: TickReason;
|
|
106
|
+
ok: boolean;
|
|
107
|
+
elapsedMs: number;
|
|
108
|
+
errorMessage?: string;
|
|
109
|
+
}
|
|
110
|
+
export interface CycleReport {
|
|
111
|
+
v: typeof PROTOCOL_VERSION;
|
|
112
|
+
startedAtMs: number;
|
|
113
|
+
endedAtMs: number;
|
|
114
|
+
outcomes: TickOutcome[];
|
|
115
|
+
newHealth: OrganHealthRecord[];
|
|
116
|
+
sig: string;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* One full cycle: decide ticks → invoke each shouldTick organ → catch any
|
|
120
|
+
* exception → update health record → produce HMAC-signed report.
|
|
121
|
+
*
|
|
122
|
+
* **Never throws** even if every organ fails — the daemon must keep running.
|
|
123
|
+
* Circuit-breaker: 3 consecutive failures opens cooldown for 1 hour.
|
|
124
|
+
*/
|
|
125
|
+
export declare function runTickCycle(input: {
|
|
126
|
+
schedules?: readonly OrganSchedule[];
|
|
127
|
+
health: OrganHealthRecord[];
|
|
128
|
+
events: EventSignals;
|
|
129
|
+
nowMs: number;
|
|
130
|
+
invoke: (organ: OrganKind) => Promise<unknown>;
|
|
131
|
+
failureThreshold?: number;
|
|
132
|
+
cooldownMs?: number;
|
|
133
|
+
secret?: string;
|
|
134
|
+
}): Promise<CycleReport>;
|
|
135
|
+
export declare function verifyCycleReport(r: CycleReport, secret?: string): boolean;
|
|
136
|
+
export interface SchedulerStats {
|
|
137
|
+
totalOrgans: number;
|
|
138
|
+
totalTicks: number;
|
|
139
|
+
totalSuccesses: number;
|
|
140
|
+
totalFailures: number;
|
|
141
|
+
successRate: number;
|
|
142
|
+
organsInCooldown: number;
|
|
143
|
+
organsHealthy: number;
|
|
144
|
+
}
|
|
145
|
+
export declare function computeStats(health: OrganHealthRecord[], nowMs: number): SchedulerStats;
|
|
146
|
+
export declare function formatStatsLine(s: SchedulerStats): string;
|
|
147
|
+
export declare function formatPlanLine(p: TickPlan): string;
|
|
148
|
+
export {};
|
|
149
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/autonomic_scheduler/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* v2.19.28 — MNEME AUTONOMIC SCHEDULER (ROOT-CAUSE FIX for dormant LIMBIC + DREAMSPACE)
|
|
3
|
+
*
|
|
4
|
+
* "daemon ทำงาน แต่ daemon ไม่ 'เรียก' LIMBIC organs อัตโนมัติ"
|
|
5
|
+
* — user audit, 2026-05-17
|
|
6
|
+
*
|
|
7
|
+
* Diagnosis: every prior release shipped organs as MCP tools and trusted
|
|
8
|
+
* that "some AI agent will call them". Reality:
|
|
9
|
+
* - AI agents don't know WHEN to call (e.g., "every 60s")
|
|
10
|
+
* - Daemon was alive but ticked only legacy (nucleus / oracle / pheromones)
|
|
11
|
+
* - .mneme/breath / .mneme/reflex / .mneme/sleep never got written
|
|
12
|
+
* - 49 organ tools = 0 invocations in practice
|
|
13
|
+
*
|
|
14
|
+
* AUTONOMIC SCHEDULER fixes ONE bug at the root: introduce a tick planner
|
|
15
|
+
* that runs every daemon heartbeat, decides which organs should fire NOW,
|
|
16
|
+
* then invokes them with per-organ backoff + fallback + circuit-breaker.
|
|
17
|
+
*
|
|
18
|
+
* 5 named schedules (each independently configurable):
|
|
19
|
+
* - BREATH every 60s (heartbeat; respawn if dead)
|
|
20
|
+
* - REFLEX on every git_event / file_save (debounced by minIntervalMs)
|
|
21
|
+
* - SLEEP every 30min during idle (consolidation cycle)
|
|
22
|
+
* - DREAMSPACE every 60min during idle (probe + cartographer cycle)
|
|
23
|
+
* - HORMONAL every 5min OR on observable event (mood update)
|
|
24
|
+
*
|
|
25
|
+
* Composes onto:
|
|
26
|
+
* - v2.19.23 BREATH (heartbeat target)
|
|
27
|
+
* - v2.19.22 REFLEX (observe + prefetch target)
|
|
28
|
+
* - v2.19.25 SLEEP TRAINING (cycle target)
|
|
29
|
+
* - v2.19.26 + 27 DREAMSPACE (probe + cartographer target)
|
|
30
|
+
* - v2.19.23 + 25 HORMONAL + ENDOCRINE (update target)
|
|
31
|
+
* - v2.19.23 THALAMUS (tier routing)
|
|
32
|
+
*
|
|
33
|
+
* Honest scope:
|
|
34
|
+
* - PURE FUNCTION decideTicks; caller (daemon) wires the actual invoker.
|
|
35
|
+
* - Per-organ circuit-breaker: 3 consecutive failures = 1hr cooldown.
|
|
36
|
+
* - Exception-handled at every level (white loop never crashes).
|
|
37
|
+
* - HMAC-chained ScheduleLedger so post-hoc audit catches missed ticks.
|
|
38
|
+
* - 24/7 always-active by design — fallback to "skipped" record on failure.
|
|
39
|
+
*/
|
|
40
|
+
import { createHmac, timingSafeEqual } from "node:crypto";
|
|
41
|
+
const PROTOCOL_VERSION = 1;
|
|
42
|
+
const DEFAULT_FAILURE_THRESHOLD = 3;
|
|
43
|
+
const DEFAULT_COOLDOWN_MS = 60 * 60 * 1000; // 1 hour
|
|
44
|
+
export const DEFAULT_SCHEDULES = [
|
|
45
|
+
{ organ: "breath", intervalMs: 60_000, fireOnEvent: false, requireIdleMs: 0 },
|
|
46
|
+
{ organ: "reflex", intervalMs: 5 * 60_000, fireOnEvent: true, requireIdleMs: 0 },
|
|
47
|
+
{ organ: "sleep", intervalMs: 30 * 60_000, fireOnEvent: false, requireIdleMs: 30 * 60_000 },
|
|
48
|
+
{ organ: "dreamspace", intervalMs: 60 * 60_000, fireOnEvent: false, requireIdleMs: 60 * 60_000 },
|
|
49
|
+
{ organ: "hormonal", intervalMs: 5 * 60_000, fireOnEvent: true, requireIdleMs: 0 },
|
|
50
|
+
];
|
|
51
|
+
export function freshHealthRecord(organ) {
|
|
52
|
+
return {
|
|
53
|
+
organ,
|
|
54
|
+
lastTickMs: 0,
|
|
55
|
+
lastSuccessMs: 0,
|
|
56
|
+
consecutiveFailures: 0,
|
|
57
|
+
cooldownUntilMs: 0,
|
|
58
|
+
totalTicks: 0,
|
|
59
|
+
totalSuccesses: 0,
|
|
60
|
+
totalFailures: 0,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
function canon(v) {
|
|
64
|
+
if (v === null || typeof v !== "object")
|
|
65
|
+
return JSON.stringify(v);
|
|
66
|
+
if (Array.isArray(v))
|
|
67
|
+
return "[" + v.map(canon).join(",") + "]";
|
|
68
|
+
const keys = Object.keys(v).sort();
|
|
69
|
+
return "{" + keys.map((k) => JSON.stringify(k) + ":" + canon(v[k])).join(",") + "}";
|
|
70
|
+
}
|
|
71
|
+
function defaultSecret() {
|
|
72
|
+
return process.env["MNEME_AUTONOMIC_SCHEDULER_SECRET"] || `mneme-autonomic-scheduler-v${PROTOCOL_VERSION}`;
|
|
73
|
+
}
|
|
74
|
+
function hmacHex(body, secret) {
|
|
75
|
+
return createHmac("sha256", secret).update(canon(body)).digest("hex");
|
|
76
|
+
}
|
|
77
|
+
function safeEqHex(a, b) {
|
|
78
|
+
try {
|
|
79
|
+
return timingSafeEqual(Buffer.from(a, "hex"), Buffer.from(b, "hex"));
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Pure decision: which organs should tick RIGHT NOW given health records +
|
|
87
|
+
* schedules + event signals + wall-clock time?
|
|
88
|
+
*
|
|
89
|
+
* Priority order per organ:
|
|
90
|
+
* 1. cooldownUntilMs > now → skip (circuit_open)
|
|
91
|
+
* 2. fireOnEvent + event present → tick (event_triggered)
|
|
92
|
+
* 3. now - lastTickMs >= interval AND idle requirement met → tick (interval_due / idle_threshold)
|
|
93
|
+
* 4. else → skip (no_reason)
|
|
94
|
+
*/
|
|
95
|
+
export function decideTicks(input) {
|
|
96
|
+
const schedules = input.schedules ?? DEFAULT_SCHEDULES;
|
|
97
|
+
const healthByOrgan = new Map(input.health.map((h) => [h.organ, h]));
|
|
98
|
+
const entries = [];
|
|
99
|
+
for (const s of schedules) {
|
|
100
|
+
const h = healthByOrgan.get(s.organ) ?? freshHealthRecord(s.organ);
|
|
101
|
+
if (input.nowMs < h.cooldownUntilMs) {
|
|
102
|
+
const remaining = Math.max(0, Math.round((h.cooldownUntilMs - input.nowMs) / 1000));
|
|
103
|
+
entries.push({
|
|
104
|
+
organ: s.organ, shouldTick: false, reason: "circuit_open",
|
|
105
|
+
details: `circuit-breaker open (${h.consecutiveFailures} consecutive failures); cooldown ${remaining}s remaining`,
|
|
106
|
+
});
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
109
|
+
const hasEvent = (s.fireOnEvent && (input.events.hasGitEvent || input.events.hasFileSaveEvent));
|
|
110
|
+
if (hasEvent) {
|
|
111
|
+
entries.push({
|
|
112
|
+
organ: s.organ, shouldTick: true, reason: "event_triggered",
|
|
113
|
+
details: `event signal received (git=${!!input.events.hasGitEvent}, file=${!!input.events.hasFileSaveEvent})`,
|
|
114
|
+
});
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
// First-tick semantics: lastTickMs===0 means "never ticked" — fire immediately
|
|
118
|
+
// so a fresh daemon doesn't sit dormant for 60s waiting for the first interval.
|
|
119
|
+
const dueByInterval = h.lastTickMs === 0 || (input.nowMs - h.lastTickMs) >= s.intervalMs;
|
|
120
|
+
const idleOk = (s.requireIdleMs ?? 0) === 0 || (input.events.idleMs ?? 0) >= (s.requireIdleMs ?? 0);
|
|
121
|
+
if (dueByInterval && idleOk) {
|
|
122
|
+
entries.push({
|
|
123
|
+
organ: s.organ, shouldTick: true,
|
|
124
|
+
reason: (s.requireIdleMs ?? 0) > 0 ? "idle_threshold" : "interval_due",
|
|
125
|
+
details: `${Math.round((input.nowMs - h.lastTickMs) / 1000)}s since last tick (interval ${Math.round(s.intervalMs / 1000)}s)`,
|
|
126
|
+
});
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
entries.push({
|
|
130
|
+
organ: s.organ, shouldTick: false, reason: "interval_due",
|
|
131
|
+
details: dueByInterval ? `awaiting idle ${Math.round(((s.requireIdleMs ?? 0) - (input.events.idleMs ?? 0)) / 1000)}s` : `${Math.round((s.intervalMs - (input.nowMs - h.lastTickMs)) / 1000)}s remaining`,
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
const body = { v: PROTOCOL_VERSION, decidedAtMs: input.nowMs, entries };
|
|
135
|
+
const sig = hmacHex(body, input.secret ?? defaultSecret());
|
|
136
|
+
return { ...body, sig };
|
|
137
|
+
}
|
|
138
|
+
export function verifyTickPlan(p, secret) {
|
|
139
|
+
const { sig, ...body } = p;
|
|
140
|
+
return safeEqHex(hmacHex(body, secret ?? defaultSecret()), sig);
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* One full cycle: decide ticks → invoke each shouldTick organ → catch any
|
|
144
|
+
* exception → update health record → produce HMAC-signed report.
|
|
145
|
+
*
|
|
146
|
+
* **Never throws** even if every organ fails — the daemon must keep running.
|
|
147
|
+
* Circuit-breaker: 3 consecutive failures opens cooldown for 1 hour.
|
|
148
|
+
*/
|
|
149
|
+
export async function runTickCycle(input) {
|
|
150
|
+
const startedAtMs = input.nowMs;
|
|
151
|
+
const plan = decideTicks({
|
|
152
|
+
schedules: input.schedules,
|
|
153
|
+
health: input.health,
|
|
154
|
+
events: input.events,
|
|
155
|
+
nowMs: input.nowMs,
|
|
156
|
+
secret: input.secret,
|
|
157
|
+
});
|
|
158
|
+
const threshold = input.failureThreshold ?? DEFAULT_FAILURE_THRESHOLD;
|
|
159
|
+
const cooldown = input.cooldownMs ?? DEFAULT_COOLDOWN_MS;
|
|
160
|
+
const healthByOrgan = new Map(input.health.map((h) => [h.organ, { ...h }]));
|
|
161
|
+
// Make sure every scheduled organ has a health record (fresh for first-time).
|
|
162
|
+
const schedules = input.schedules ?? DEFAULT_SCHEDULES;
|
|
163
|
+
for (const s of schedules) {
|
|
164
|
+
if (!healthByOrgan.has(s.organ))
|
|
165
|
+
healthByOrgan.set(s.organ, freshHealthRecord(s.organ));
|
|
166
|
+
}
|
|
167
|
+
const outcomes = [];
|
|
168
|
+
for (const entry of plan.entries) {
|
|
169
|
+
const h = healthByOrgan.get(entry.organ);
|
|
170
|
+
if (!entry.shouldTick) {
|
|
171
|
+
outcomes.push({
|
|
172
|
+
organ: entry.organ, shouldTick: false, reason: entry.reason,
|
|
173
|
+
ok: false, elapsedMs: 0,
|
|
174
|
+
});
|
|
175
|
+
continue;
|
|
176
|
+
}
|
|
177
|
+
const tickStart = Date.now();
|
|
178
|
+
h.lastTickMs = input.nowMs;
|
|
179
|
+
h.totalTicks++;
|
|
180
|
+
try {
|
|
181
|
+
await input.invoke(entry.organ);
|
|
182
|
+
h.consecutiveFailures = 0;
|
|
183
|
+
h.cooldownUntilMs = 0;
|
|
184
|
+
h.lastSuccessMs = input.nowMs;
|
|
185
|
+
h.totalSuccesses++;
|
|
186
|
+
outcomes.push({
|
|
187
|
+
organ: entry.organ, shouldTick: true, reason: entry.reason,
|
|
188
|
+
ok: true, elapsedMs: Date.now() - tickStart,
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
catch (e) {
|
|
192
|
+
h.consecutiveFailures++;
|
|
193
|
+
h.totalFailures++;
|
|
194
|
+
if (h.consecutiveFailures >= threshold) {
|
|
195
|
+
h.cooldownUntilMs = input.nowMs + cooldown;
|
|
196
|
+
}
|
|
197
|
+
outcomes.push({
|
|
198
|
+
organ: entry.organ, shouldTick: true, reason: entry.reason,
|
|
199
|
+
ok: false, elapsedMs: Date.now() - tickStart,
|
|
200
|
+
errorMessage: e.message,
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
const newHealth = Array.from(healthByOrgan.values());
|
|
205
|
+
const body = {
|
|
206
|
+
v: PROTOCOL_VERSION,
|
|
207
|
+
startedAtMs,
|
|
208
|
+
endedAtMs: Date.now(),
|
|
209
|
+
outcomes,
|
|
210
|
+
newHealth,
|
|
211
|
+
};
|
|
212
|
+
const sig = hmacHex(body, input.secret ?? defaultSecret());
|
|
213
|
+
return { ...body, sig };
|
|
214
|
+
}
|
|
215
|
+
export function verifyCycleReport(r, secret) {
|
|
216
|
+
const { sig, ...body } = r;
|
|
217
|
+
return safeEqHex(hmacHex(body, secret ?? defaultSecret()), sig);
|
|
218
|
+
}
|
|
219
|
+
export function computeStats(health, nowMs) {
|
|
220
|
+
let totalTicks = 0, totalSuccesses = 0, totalFailures = 0, inCooldown = 0, healthy = 0;
|
|
221
|
+
for (const h of health) {
|
|
222
|
+
totalTicks += h.totalTicks;
|
|
223
|
+
totalSuccesses += h.totalSuccesses;
|
|
224
|
+
totalFailures += h.totalFailures;
|
|
225
|
+
if (h.cooldownUntilMs > nowMs)
|
|
226
|
+
inCooldown++;
|
|
227
|
+
else if (h.consecutiveFailures === 0)
|
|
228
|
+
healthy++;
|
|
229
|
+
}
|
|
230
|
+
return {
|
|
231
|
+
totalOrgans: health.length,
|
|
232
|
+
totalTicks,
|
|
233
|
+
totalSuccesses,
|
|
234
|
+
totalFailures,
|
|
235
|
+
successRate: totalTicks === 0 ? 1 : totalSuccesses / totalTicks,
|
|
236
|
+
organsInCooldown: inCooldown,
|
|
237
|
+
organsHealthy: healthy,
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
export function formatStatsLine(s) {
|
|
241
|
+
const pct = (s.successRate * 100).toFixed(1);
|
|
242
|
+
return `🩺 SCHEDULER · ${s.totalOrgans} organs · ${s.totalTicks} ticks · ${pct}% success · ❤️${s.organsHealthy} 🧊${s.organsInCooldown}`;
|
|
243
|
+
}
|
|
244
|
+
export function formatPlanLine(p) {
|
|
245
|
+
const will = p.entries.filter((e) => e.shouldTick).map((e) => `${e.organ}(${e.reason})`).join(",");
|
|
246
|
+
const skip = p.entries.filter((e) => !e.shouldTick).length;
|
|
247
|
+
return `🩺 PLAN · will=[${will || "none"}] · skip=${skip}`;
|
|
248
|
+
}
|
|
249
|
+
//# sourceMappingURL=index.js.map
|