feat: SignalSource abstraction — generalize signal ingestion beyond Todoist (#78)

- Add Signal + SignalSource interfaces to packages/shared-types
- TipCandidate.features widened to Record<string,number|boolean> to match Signal
- TodoistSignalSource: encapsulates fetch, cache, 401 handling, bus events, and act()
- SignalAggregator: parallel fan-out across sources with per-source failure isolation
- Recommender refactored to consume Signal[] via aggregator; source action dispatch via aggregator.act()
- ADR-0009: signal normalization strategy

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-18 01:11:56 +00:00
parent 46dee7377e
commit e3ca3ba733
8 changed files with 289 additions and 122 deletions

View File

@@ -62,7 +62,7 @@ describe('POST /recommend integration', () => {
const mod = await import('../recommender.js');
const { recommenderRouter } = mod;
clearCache = (mod as any)._clearTaskCacheForTests;
clearCache = (mod as any)._clearCandidateCacheForTests;
const app = express();
app.use(express.json());
app.use('/api', recommenderRouter);