fix bruno collection

This commit is contained in:
Kazuma
2026-06-06 21:49:31 -04:00
parent 2e7860637e
commit 76c2a671f4
25 changed files with 4361 additions and 94 deletions
@@ -44,7 +44,9 @@ export class ScreenerEngine {
// eslint-disable-next-line no-console
this.logger = logger ?? {
write: (msg: string) => process.stdout.write(msg),
// eslint-disable-next-line no-console
log: (...args: unknown[]) => console.log(...args),
// eslint-disable-next-line no-console
warn: (...args: unknown[]) => console.warn(...args),
};
}
+13 -9
View File
@@ -4,15 +4,10 @@ import { CatalystCache, CatalystAnalyst } from '../../domains/shared';
import { analyzeSchema } from '../../domains/shared/types/schemas';
export class AnalyzeController {
private readonly catalystAnalyst: CatalystAnalyst;
constructor(
private readonly catalystCache: CatalystCache,
private readonly llm: LLMAnalyst,
) {
// Create a fresh instance for per-ticker story fetching (not cached)
this.catalystAnalyst = new CatalystAnalyst();
}
) {}
register(app: FastifyInstance): void {
app.post(
@@ -27,13 +22,22 @@ export class AnalyzeController {
return reply.code(400).send({ error: 'ANTHROPIC_API_KEY is not set in .env' });
}
const tickers = (req.body as { tickers: string[] }).tickers.map((t) => t.toUpperCase());
const requestedTickers = (req.body as { tickers: string[] }).tickers.map((t) =>
t.toUpperCase(),
);
// Use cached catalyst data (refreshed every 15 minutes)
const { stories: allStories } = await this.catalystCache.get();
// Filter stories to only those matching requested tickers
const stories = allStories.filter((story) =>
story.tickers.some((t) => requestedTickers.includes(t)),
);
const stories = await this.catalystAnalyst.fetchStoriesForTickers(tickers);
if (!stories.length) return reply.code(200).send({ analysis: null, reason: 'no_stories' });
const { tickerFrequency } = CatalystAnalyst.rankTickers(stories);
const analysis = await this.llm.analyze(stories, tickers, tickerFrequency);
const analysis = await this.llm.analyze(stories, requestedTickers, tickerFrequency);
return { analysis };
}
}
@@ -21,9 +21,14 @@ export class BondScorer {
if (metrics.creditRatingNumeric < gates.minCreditRating) {
return {
label: '🔴 Avoid',
scoreSummary: `Gate failed: ${metrics.creditRating} (${metrics.creditRatingNumeric}) < ${gates.minCreditRating}`,
audit: { passedGates: false },
label: '🔴 REJECT',
scoreSummary: `Credit rating gate failed: ${metrics.creditRating} (${metrics.creditRatingNumeric}) < ${gates.minCreditRating}`,
audit: {
passedGates: false,
failures: [
`creditRating: ${metrics.creditRating} (${metrics.creditRatingNumeric}) < ${gates.minCreditRating}`,
],
},
};
}
+15 -2
View File
@@ -17,11 +17,24 @@ export class EtfScorer {
fiveYearReturn: parseFloat(String(m.fiveYearReturn)) || 0,
};
const failures: string[] = [];
if (metrics.expenseRatio > gates.maxExpenseRatio) {
failures.push(`Expense ratio: ${metrics.expenseRatio} > ${gates.maxExpenseRatio}`);
}
if (
thresholds.minFiveYearReturn != null &&
metrics.fiveYearReturn < thresholds.minFiveYearReturn
) {
failures.push(`5-year return: ${metrics.fiveYearReturn}% < ${thresholds.minFiveYearReturn}%`);
}
if (thresholds.minVolume != null && metrics.volume < thresholds.minVolume) {
failures.push(`Volume: ${metrics.volume} < ${thresholds.minVolume}`);
}
if (failures.length > 0) {
return {
label: '🔴 REJECT',
scoreSummary: 'Gate failed: High Expense Ratio',
audit: { passedGates: false },
scoreSummary: `Gate failed: ${failures.map((f) => f.split(':')[0]).join(', ')}`,
audit: { passedGates: false, failures },
};
}