bulltrackers-module 1.0.335 → 1.0.337

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.
@@ -6,4 +6,5 @@ module.exports = {
6
6
 
7
7
  "instrument-price-change-1d": { maxZeroPct: 100 }, // Because weekeends/holidays return 0 change, technically crypto means this can't hit 100% but it's usually quite close, so we override
8
8
  "instrument-price-momentum-20d ": { maxZeroPct: 100 }, // Some assets can be very stagnant over a month, especially bonds or stablecoins
9
+ "mimetic-latency": { maxFlatlinePct: 100 },
9
10
  };
@@ -3,6 +3,7 @@
3
3
  * PURPOSE: Sequential Cursor-Based Dispatcher.
4
4
  * BEHAVIOR: Dispatch -> Wait ETA -> Next Date.
5
5
  * UPDATED: Added "Sweep" Protocol for OOM recovery & High-Mem Verification.
6
+ * UPDATED: Added checks to permanently skip Deterministic Failures (Quality Breakers).
6
7
  */
7
8
 
8
9
  const { getExpectedDateStrings, getEarliestDataDates, normalizeName, DEFINITIVE_EARLIEST_DATES } = require('../utils/utils.js');
@@ -22,7 +23,7 @@ const STALE_LOCK_THRESHOLD_MS = 1000 * 60 * 15;
22
23
  // =============================================================================
23
24
  async function filterActiveTasks(db, date, pass, tasks, logger, forceRun = false) {
24
25
  if (!tasks || tasks.length === 0) return [];
25
- if (forceRun) return tasks; // Bypass check for Sweep Mode
26
+ if (forceRun) return tasks; // Bypass check for Sweep Mode (Handled separately in Sweep logic)
26
27
 
27
28
  const checkPromises = tasks.map(async (t) => {
28
29
  const taskName = normalizeName(t.name);
@@ -54,6 +55,16 @@ async function filterActiveTasks(db, date, pass, tasks, logger, forceRun = false
54
55
  (Date.now() - new Date(data.completedAt).getTime() < 60 * 1000);
55
56
 
56
57
  if (isJustFinished) return null;
58
+
59
+ // 3. DETERMINISTIC FAILURE CHECK (Break Infinite Loops)
60
+ // If the task failed due to Logic/Quality issues, never retry it automatically.
61
+ if (data.status === 'FAILED') {
62
+ const stage = data.error?.stage;
63
+ if (['QUALITY_CIRCUIT_BREAKER', 'SEMANTIC_GATE', 'SHARDING_LIMIT_EXCEEDED'].includes(stage)) {
64
+ if (logger) logger.log('WARN', `[Dispatcher] 🛑 Skipping deterministic failure for ${taskName} (${stage}).`);
65
+ return null;
66
+ }
67
+ }
57
68
  }
58
69
  return t;
59
70
  });
@@ -249,12 +260,34 @@ async function handleSweepDispatch(config, dependencies, computationManifest, re
249
260
  return { dispatched: 0 };
250
261
  }
251
262
 
263
+ // [FIX] Filter out deterministic failures from Sweep to prevent loops
264
+ // Sweep is for OOM recovery. Quality failures will fail on High-Mem too.
265
+ const validTasks = [];
266
+ for (const task of pending) {
267
+ const name = normalizeName(task.name);
268
+ const ledgerPath = `computation_audit_ledger/${date}/passes/${passToRun}/tasks/${name}`;
269
+ const doc = await db.doc(ledgerPath).get();
270
+ if (doc.exists) {
271
+ const data = doc.data();
272
+ const stage = data.error?.stage;
273
+ if (['QUALITY_CIRCUIT_BREAKER', 'SEMANTIC_GATE', 'SHARDING_LIMIT_EXCEEDED'].includes(stage)) {
274
+ logger.log('WARN', `[Sweep] 🛑 Skipping deterministic failure for ${name} (${stage}).`);
275
+ continue;
276
+ }
277
+ }
278
+ validTasks.push(task);
279
+ }
280
+
281
+ if (validTasks.length === 0) {
282
+ logger.log('INFO', `[Sweep] ${date} only has deterministic failures. No dispatch.`);
283
+ return { dispatched: 0 };
284
+ }
285
+
252
286
  // 2. FORCE High Mem & Skip Zombie Check
253
- // We do NOT filterActiveTasks because we assume they might be OOM'd zombies
254
- // We do NOT check resource tier from previous runs, we FORCE 'high-mem'
287
+ // We use validTasks now
255
288
  const currentDispatchId = crypto.randomUUID();
256
289
 
257
- const tasksPayload = pending.map(t => ({
290
+ const tasksPayload = validTasks.map(t => ({
258
291
  ...t,
259
292
  action: 'RUN_COMPUTATION_DATE',
260
293
  computation: t.name,
@@ -1,6 +1,7 @@
1
1
  /**
2
2
  * FILENAME: computation-system/helpers/computation_worker.js
3
3
  * UPDATED: Fixed Firestore 'undefined' field error for dispatchId.
4
+ * UPDATED: Writes structured Error objects (with stage) to Ledger to prevent retry loops.
4
5
  */
5
6
 
6
7
  const { executeDispatchTask } = require('../WorkflowOrchestrator.js');
@@ -92,7 +93,19 @@ async function handleComputationTask(message, config, dependencies) {
92
93
  const isDeterministic = ['SHARDING_LIMIT_EXCEEDED', 'QUALITY_CIRCUIT_BREAKER', 'SEMANTIC_GATE'].includes(err.stage);
93
94
 
94
95
  if (isDeterministic || (message.deliveryAttempt || 1) >= MAX_RETRIES) {
95
- await db.doc(ledgerPath).set({ status: 'FAILED', error: err.message, failedAt: new Date() }, { merge: true });
96
+ // [FIX] Write structured error payload so Dispatcher can see the 'stage'
97
+ // This prevents the Dispatcher from retrying Quality Broken tasks.
98
+ const errorPayload = {
99
+ message: err.message,
100
+ stage: err.stage || 'FATAL'
101
+ };
102
+
103
+ await db.doc(ledgerPath).set({
104
+ status: 'FAILED',
105
+ error: errorPayload,
106
+ failedAt: new Date()
107
+ }, { merge: true });
108
+
96
109
  await recordRunAttempt(db, { date, computation, pass }, 'FAILURE', { message: err.message, stage: err.stage || 'FATAL' }, { peakMemoryMB: heartbeat.getPeak() }, triggerReason, resourceTier);
97
110
  return;
98
111
  }
@@ -3,4 +3,4 @@
3
3
  * PURPOSE: Master override for BuildReporter.
4
4
  * Increment this string to force a full re-analysis regardless of code or data stability.
5
5
  */
6
- module.exports = "reporter-epoch-4";
6
+ module.exports = "reporter-epoch-5";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bulltrackers-module",
3
- "version": "1.0.335",
3
+ "version": "1.0.337",
4
4
  "description": "Helper Functions for Bulltrackers.",
5
5
  "main": "index.js",
6
6
  "files": [