feat(dispatcher): periodic recommender cron + persistent repo registry#142
Conversation
#135) Closes the last gap to 'mm start' + walk-away: the recommender ran only on a manual trigger, and the daemon's repo map was in-memory (empty at startup), so a cron would have no repos to iterate. - Migration 004: add repo_config.checkout_path — a row with a non-null path IS a 'managed repo'. The persistent registry (repo_config already keyed per-repo). - repo-config: registerManagedRepo / getManagedRepoPath / listManagedRepos + getLastRecommenderRun / markRecommenderRun. - recommender-cron.ts (mirrors poller/watchdog crons): every minute, a due-check over managed + recommender-enabled + unpaused repos — stamps last_recommender_run BEFORE firing (no double-dispatch) and runs the recommender for any whose interval_minutes has elapsed. enabled gates periodic running; auto_dispatch is the separate downstream gate. - main.ts: hydrate repoPaths from the registry on startup; persist on every learned path (dispatch / trigger) via rememberRepoPath; extract runRecommenderForRepo shared by the /trigger route and the cron; start + shut down the cron. - mm init registers the repo (registerRepo seam → daemon db write), so a freshly- init'd repo is cron-eligible cold with zero priming.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
📝 WalkthroughWalkthroughAdds a durable managed-repo registry and migration, a recommender cron pass and scheduler, dispatcher hydration and wiring to persist checkout paths and run recommenders, and a CLI callback to register repos in the daemon after init. ChangesRecommender Cron and Managed Repo Registry
Sequence DiagramsequenceDiagram
participant Cron as Recommender Cron Pass
participant DB as Dispatcher DB
participant Dispatcher as Dispatcher (runRecommenderForRepo)
participant Repo as Repo Checkout Path
participant Recommender as dispatchRecommender
Cron->>DB: listManagedRepos()
DB-->>Cron: managed repos with checkout_path
loop For each managed repo
Cron->>Dispatcher: runRecommenderForRepo(checkoutPath)
Dispatcher->>DB: markRecommenderRun(repo) -- stamp before run
Dispatcher->>Recommender: dispatchRecommender(repo, triggerAutoDispatch)
Recommender->>Dispatcher: triggerAutoDispatch -> scheduleAutoDispatch(repo)
end
🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs:
Suggested labels: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 ESLint
ESLint skipped: no ESLint configuration detected in root package.json. To enable, add Comment |
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/dispatcher/src/main.ts`:
- Around line 450-452: The cron callback currently ignores the result of
runRecommenderForRepo; change runRecommender to await the returned result (e.g.,
const result = await runRecommenderForRepo(checkoutPath)) and check its status
field, throwing or returning an error when result.status !== 202 so non-202
launches (400/500/etc.) propagate as failures; reference runRecommender and
runRecommenderForRepo when making this change and include the response body in
the thrown error/log for debugging.
In `@packages/dispatcher/src/recommender-cron.ts`:
- Around line 22-33: Add a TSDoc/JSDoc comment above the exported
RecommenderCronDeps type describing its purpose and usage (it represents the
dependencies required by the recommender cron job), then keep the existing
inline field comments for db, loadRepoConfig, runRecommender, and now; ensure
the top-level comment appears immediately before the RecommenderCronDeps
declaration so the module export rule recognizes it.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 829afd41-0e0c-4888-bb55-86a6aaba4556
📒 Files selected for processing (11)
packages/cli/src/commands/init.tspackages/cli/src/index.tspackages/cli/test/init-register.test.tspackages/dispatcher/src/db/migrations/004_repo_checkout_path.sqlpackages/dispatcher/src/index.tspackages/dispatcher/src/main.tspackages/dispatcher/src/recommender-cron.tspackages/dispatcher/src/repo-config.tspackages/dispatcher/test/db.test.tspackages/dispatcher/test/recommender-cron.test.tspackages/dispatcher/test/repo-config.test.ts
…ronDeps CodeRabbit on #142: - the cron's runRecommender ignored runRecommenderForRepo's {status,body}, so a non-202 (bad config / unresolvable repo) counted as a fired run. Throw on non-202 so the per-repo catch logs it and doesn't count it; the repo stays stamped (retries next interval, no spin). - add the missing top-level TSDoc block on the exported RecommenderCronDeps.
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
Closes #135.
What
The last piece for
mm start+ walk-away: the recommender now runs on a schedule for every managed repo, and the daemon's repo registry is persistent (survives restart, and is populated bymm initso a fresh repo is cron-eligible cold).Before this, the recommender ran only via a manual
/trigger/recommender, and the daemon'srepoPathswas in-memory + empty at startup — so a cron would have had no repos to iterate.How
repo_config.checkout_path(nullable). A row with a non-null path is a "managed repo".repo_configalready keyed per-repo state (paused_until,last_recommender_run); this adds the one missing fact: where the checkout lives.repo-config.ts) —registerManagedRepo(upsert, preserves pause/bookkeeping),getManagedRepoPath,listManagedRepos,getLastRecommenderRun,markRecommenderRun.recommender-cron.ts— mirrorspoller-cron/watchdog-cron. Ticks every minute as a due-check: for each managed, recommender-enabled, unpaused repo whoselast_recommender_runis older than itsinterval_minutes, it stamps the run time BEFORE firing (so an overlapping/slow tick can't double-dispatch) and runs the recommender.enabledgates periodic running;auto_dispatchstays the separate downstream gate (so a repo can run ranking-only on a schedule).main.ts— hydratesrepoPathsfrom the registry on startup;rememberRepoPathpersists every learned path (dispatch / trigger); extractsrunRecommenderForRepo(shared by the/trigger/recommenderroute and the cron, so both behave identically); starts + tears down the cron.mm init— registers the repo in the daemon DB via aregisterReposeam (the CLI entry wires it to aregisterManagedRepowrite), best-effort. A freshly-init'd repo joins the registry with zero priming.How to verify
What to verify
repo-config.test.ts.interval_minutes; non-positive interval never runs; stamps-before-firing so a throwing run isn't retried (and is isolated); ignores unmanaged rows —recommender-cron.test.ts.mm initregisters(slug, resolved path)on success, not on--dry-run, and a registry-write failure doesn't fail init —init-register.test.ts.db.test.ts.Dogfood after merge
Review notes
mm initopens the daemon DB (openAndMigrateat the configureddb_path) to write the registry row. WAL mode (already on) makes this safe alongside a running daemon;openAndMigrateis idempotent. Best-effort — wrapped so a write failure never fails init.loadRepoConfig+runRecommender) so the pass unit-tests with no engine/gh.Summary by CodeRabbit
New Features
Chores
Tests