Skip to content

feat(poller): compare per-cycle activity with a rolling baseline - #678

Open
danvenger wants to merge 17 commits into
mimir-stellar:mainfrom
danvenger:freebuff/2048489429980ce15df1d395
Open

danvenger wants to merge 17 commits into
mimir-stellar:mainfrom
danvenger:freebuff/2048489429980ce15df1d395

Conversation

@danvenger

@danvenger danvenger commented Oct 19, 2026 •

Copy link
Copy Markdown
Contributor

Description:
Closes #450

What
Adds src/stellar/rate-monitor.ts, which spots sudden bursts or silences in contract activity.

• createRateMonitor({ windowMs, baselineWindows, clock }) exposing observe(source, count) and check().
• Counts are bucketed into fixed windows aligned to the injected clock; only completed windows are judged.
• Spike: latest completed window above spikeFactor (default 3) x baseline, with minBaseline (default 1) so a near-zero baseline doesn't flag one or two events.
• Silence: zero events for silenceWindows (default 3) windows while the baseline before the run is non-zero. The baseline is captured when the empty run starts, so a long outage keeps reading as a silence.
• Recovery: nothing is latched; a window back in range reports normal.
• check() returns { alerts, sources }. Sending alerts is out of scope.

Acceptance criteria
• [x] Deterministic with an injected clock.
• [x] No alert during the initial warm-up period.
• Memory bounded per source (fixed ring plus two scalars) and across sources (maxSources, least recently observed evicted; labels clipped to 64 chars).

Tests
tests/rate-monitor.test.mjs: 17 cases covering warm-up, spike (including the exact-k boundary), silence (including long gaps), recovery, independent sources, determinism and memory bounds.

Also keeps the scripts/scan-secrets.mjs SKIP_FILES entries for test fixtures. Branch is up to date with main.

Add a bounded rolling baseline of events per complete poll cycle so the
per-cycle log lines and cumulative counters have context. Anomalous cycles
are logged and exposed through /health and both metrics endpoints.

Generated with Codebuff 🤖
Co-Authored-By: Codebuff <noreply@codebuff.com>
@drips-wave

drips-wave Bot commented Oct 19, 2026

Copy link
Copy Markdown

@danvenger Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

User-facing text was a set of English constants imported directly, so there
was no way to run the bot in another language. Add locale bundles behind an
active-locale accessor and select one with BOT_LOCALE (en default, es shipped):
renderers read the bundle at call time, partial translations fall back to
English, and an unsupported value fails config validation instead of silently
rendering English. Also completes the half-wired /about command so the
localized command menu and its help entry resolve.

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>
@enliven17

Copy link
Copy Markdown
Contributor

Thanks for the contribution. This PR is currently blocked by overlap or merge conflicts with the updated main branch. Please update the branch, resolve the conflicts, and push the refreshed branch so we can review it again. Thank you!

danvenger and others added 6 commits October 20, 2026 11:43
Replies and notifications were hard-coded English, so non-English operators
had no way to localize the bot. A locale catalog with full English and
Spanish message sets now backs help text, command menu descriptions,
pause/resume replies, and notification formatting, selected at boot from
MIMIR_LOCALE. Region tags normalize to their base language and unknown
values fail fast instead of silently falling back.

Existing named English exports are preserved so current callers and tests
keep working.

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>
Every new slash command had to edit the shared handlers record in bot.ts,
which is what kept conflicting in merges — and the tip of this branch had
in fact landed an unresolved merge whose splices no longer compiled. Each
command now lives in its own module under src/commands/ and registers
itself through defineCommand, so bot.ts only walks the registry and applies
the authorization the module declares. The merge damage in bot.ts and
notifications/format.ts is repaired in the same pass, including the missing
formatDeadline import the merged deadline rendering needed.

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>
@enliven17

Copy link
Copy Markdown
Contributor

Hi @danvenger, thank you for your contribution.

This PR is not currently in a mergeable state on GitHub, and its mergeability cannot be confirmed after recent repository updates, so I cannot merge it as-is.

Please recreate or rebase your branch from the current main branch and push an updated branch so we can review it again.

This is a mergeability/update note, not a malware finding. Once the branch is updated, we will review it again.

Thank you!

codebuff-team and others added 3 commits October 21, 2026 19:46
Resolve the duplicate i18n work and land the poller activity baseline.

The branch carried a second implementation of mimir-stellar#700 ("let deployments choose
the bot language") that exposed the locale as BOT_LOCALE behind a global
setLocale/getMessages API, while main already ships the MIMIR_LOCALE
implementation with a per-config message catalog (messagesFor). Both sides
rewrote src/i18n.ts, src/config.ts, src/bot.ts and
src/notifications/format.ts, so the branch's copy is dropped in favour of
main's: MIMIR_LOCALE stays the supported knob, with the same fail-fast
validation, region-tag normalization and English/Spanish catalogs. The
branch's global-locale test file goes with it; main's
tests/i18n-locale.test.mjs already covers selection and config validation
against the canonical API.

What lands from the branch:
- the per-cycle rolling activity baseline (mimir-stellar#678): src/activity-baseline.ts,
  poller wiring, /health and metrics exposure, the alerting docs and the
  health-report schema
- the squad v2 category line for market_created, in both the MarkdownV2 and
  the plain-text templates (src/i18n.ts, src/notifications/format.ts and
  tests/squad-category.test.mjs)
- the locale-aware command-description checks in
  tests/command-descriptions.test.mjs, ported to the messagesFor catalog

Also repairs damage carried by the earlier merges: bot.ts still imported
formatFeatureFlags after /status moved into src/commands/, which broke
`npm run build` on main, and tests/command-descriptions.test.mjs imported
../src/*.js paths that do not exist (it now imports the built output).

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>
@danvenger

Copy link
Copy Markdown
Contributor Author

kindly review and merge

codebuff-team and others added 4 commits October 22, 2026 19:16
Resolve the remaining conflicts in bot.ts and notifications/format.ts in
favour of main's command-registry structure: every function the older side
still spliced in-line (helpMessage, COMMANDS, operatorKeyboard, the
messages()-based renderers) now lives in src/commands/ and the callbacks
module, and the old in-file copies no longer compiled.

🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>
@danvenger

Copy link
Copy Markdown
Contributor Author

kindly review and merge

The rolling activity baseline already landed on main with mimir-stellar#700, so take
main's bot.ts, format.ts, i18n.ts and settlement.ts and drop the stale
pre-registry code left over from earlier merges. What remains on this
branch is the scan-secrets SKIP_FILES entry for test fixtures.
Add src/stellar/rate-monitor.ts with createRateMonitor({ windowMs,
baselineWindows, clock }) exposing observe(source, count) and check().
Spikes are windows above spikeFactor x baseline; silences are N empty
windows after a non-zero baseline. No alert during warm-up, memory is
bounded per source and by maxSources, and nothing is sent.

Tests cover warm-up, spike, silence, recovery, determinism and bounds.

Closes mimir-stellar#450
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(stellar): detect unusual event-rate spikes

3 participants