fix(ideas): wire up rule-based idea engine as LLM fallback - #133
Open
Chirag6722 wants to merge 1 commit into
Open
fix(ideas): wire up rule-based idea engine as LLM fallback#133Chirag6722 wants to merge 1 commit into
Chirag6722 wants to merge 1 commit into
Conversation
generateIdeas() has been fully implemented and imported by server.mjs since v2.0.0, but was never called. Every user without an LLM key saw a permanently empty "Leverageable Ideas" panel, and any transient LLM failure (timeout, 429, malformed JSON) blanked the panel for that sweep — even though all the input signals needed for deterministic ideas were already in the synthesized data. - Add resolveIdeas(), a shared resolver that prefers LLM ideas and falls back to the signal-rule engine when the provider is absent, empty, or throws. Used by both the server sweep cycle and the `npm run inject` CLI path. - synthesize() now seeds baseline ideas, so the instant-load path (existing runs/latest.json) shows a populated panel before the first sweep finishes. - Harden generateIdeas() against degraded sweeps: a failed FRED/EIA/BLS/Telegram source no longer throws, non-finite metric values no longer emit ideas with NaN in user-facing copy, and a zero oldest WTI price no longer divides by zero. - Dashboard: SIGNAL BASED provenance badge for rule-generated ideas, and a source-aware empty state (en/fr locales) instead of always blaming the LLM. - Add `npm test` so the suite is runnable, plus 22 tests covering each rule's trigger, the 8-idea cap, the output contract the dashboard renders, and all four fallback paths. Closes calesthio#132 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #132
What was broken
generateIdeas()indashboard/inject.mjs— the 11-rule cross-domain signal engine — has been imported byserver.mjssince the initial v2.0.0 release (ef2c647) and never called. The Ideas panel was only ever populated by the LLM path:So every user without an LLM key saw a permanently empty "Leverageable Ideas" panel, and any transient provider failure (timeout — see #87 — a 429, or malformed JSON) blanked the panel for that sweep, even though every input signal needed to produce deterministic ideas was already sitting in
synthesized.README.md:126already documented the intended behaviour — "AI-generated trade ideas (with LLM) or signal-correlated ideas (without)" — the code just never implemented the second half.What this PR does
Wires the fallback. New
resolveIdeas(llmProvider, V2, delta, previousIdeas)indashboard/inject.mjsprefers LLM ideas and falls back togenerateIdeas()when the provider is absent, returns nothing, or throws. It never throws, so a provider outage cannot take down the sweep or blank the panel. Both call sites —runSweepCycle()inserver.mjsandcliInject()(npm run inject) — now share it, replacing two divergent copies of the same branching.Seeds baseline ideas in
synthesize(). The instant-load path (runs/latest.jsonon startup) previously showed an empty panel until the first sweep finished; it now renders ideas immediately.Hardens
generateIdeas()for degraded sweeps. It previously dereferencedV2.fred,V2.tg.urgent,V2.energy.wtiRecent,V2.bls,V2.thermalandV2.treasuryunguarded — a failed FRED or EIA source would throw and, now that it is on the sweep path, take the whole cycle down. Also:Number.isFinite, so anull-valued FRED series no longer emitsVIX at nullcopy;Infinity%).Makes the provenance visible. New
ideasBadge()rendersSIGNAL BASEDforideasSource === 'rules'alongside the existingAI ENHANCED, and the empty state is now source-aware (NO SIGNAL TRIGGERS) rather than always blaming an unconfigured LLM.en+frlocale strings added.Adds
npm test. The 9 existing test files undertest/had no runner —package.jsonhad notestscript anddocker-publish.ymlnever invokes one. Added"test": "node --test \"test/*.test.mjs\""so the existing 46 tests and the new ones are actually runnable.Tests
22 new tests in
test/ideas-rules.test.mjs:null/undefinedinput,{}(all sources failed), andnull-valued metrics all return[]instead of throwing or emittingNaNcopy.title/text/type/confidence/horizonfieldsjarvis.htmlreads, with values from the sets the CSS classes and rendering expect, and noNaN/Infinity/undefinedin user-facing text.ideasSource: 'rules'with a non-empty list; provider returns valid ideas →ideasSource: 'llm'.(46 → 68 tests; the one skip is the pre-existing network-gated integration test.)
Verified end-to-end against the real sweep baked into
jarvis.html, with no LLM configured — 7 ideas where the panel was previously empty:Notes
ideasSourcegains'rules'and no longer emits'disabled'or'llm-failed'. The dashboard'selsebranch still rendersPENDING, so an older cached value degrades gracefully rather than breaking.FOR INFORMATIONAL PURPOSES ONLYdisclosure on the panel is unchanged and applies equally to rule-generated ideas.🤖 Generated with Claude Code