Improve horse facts ux #17

Closed
opened 2026-07-30 07:59:40 +00:00 by alex · 2 comments
Owner

So far is pretty boring and repeating.

Search the web to find out if we can source from an API or web service instead of our static list.

So far is pretty boring and repeating. Search the web to find out if we can source from an API or web service instead of our static list.
Author
Owner

/pi new pr

/pi new pr
Contributor

Let me look at the remaining test files and check whether I have network access to research APIs.Now let me check whether I have network access to research available horse facts APIs.I have network access. Let me research horse facts APIs more and read the storage modules to match conventions.I have network access and have completed my research. Let me verify one more API shape (the JSON response formats) so my implementation is accurate.My research is complete. Here's what I found:

  • No reliable, dedicated horse facts API exists. horsefacts.org is a parked landing page (404 on /api).
  • The closest free, no-key APIs are generic trivia: catfact.ninja/fact{"fact":"..."} and uselessfacts.jsph.pl/.../random{"text":"..."} — neither is horse-specific.
  • Most other fact APIs require API keys.

Given the bot's resilience-first design, I'll implement: (1) a non-repeating shuffle-deck so facts stop repeating, (2) a much larger curated list, and (3) an optional API-backed source with graceful fallback to the curated deck. Let me build it.Now the persistence store for the deck state:Now let me add the config for the optional API source and store path:Now let me update main.ts to wire the deck and optional API provider:Now let me add the createFactProvider helper to main.ts. Let me place it near broadcastFact:Now let me update the existing broadcastFact test for the new async signature:Now let me update facts_test.ts — the data-integrity tests still apply, and I'll add thorough tests for shuffle, FactDeck, and fetchApiFact:Now let me create the fact-store_test.ts:Now let me add config tests for the new facts settings:Now let me update the .env.example and README. First let me check the current Deno version and run the tests:FactsSettings lives in config.ts, not facts.ts. Let me fix the import in main.ts:The reconciliation test over-drew (crossing a cycle boundary). Let me fix it to assert only what reconciliation actually guarantees:All 180 tests pass. Now let me run the linter, formatter, type check, and Fallow static analysis:Type check passes. Let me fix the unused import:Lint is clean. Now let me run Fallow (dead-code analysis) and verify formatting:Fallow found issues. Since HORSE_FACTS is now actually consumed by main.ts, its suppression is stale. And pickRandomFact is now dead code (superseded by FactDeck). Let me clean these up: remove pickRandomFact and fix the suppressions.Now remove the pickRandomFact import and its tests from facts_test.ts:Let me re-read the current state of the test file to make precise edits:The trailing prose in the suppression comment confused Fallow's parser. Let me use the exact recognized form:Fallow is clean. Now let me run the full test suite once more to confirm everything passes:All tests pass. Now let me update the documentation — .env.example and the README:I accidentally removed the feeds section. Let me restore it after the new facts section:Now let me update the README — the config table and the "Daily horse facts" section:Now let me update the "Daily horse facts" section in the README to describe the new behavior:Let me update the project structure section in the README to mention the new file:Now let me run the full check suite once more (fmt, lint, check, test, fallow) to make sure everything is green:The README needs formatting. Let me apply fmt:Everything is green. Let me do a final review of the complete diff:Let me verify the new untracked files are included and review the final config wiring:Let me verify the final main.ts wiring:All wiring looks correct. Let me run one final comprehensive check to confirm a clean state before creating the PR:All green: fmt, lint, type-check, 176 tests, and Fallow dead-code analysis all pass. Now let me create the PR:PR #18 created. Here's a summary of what I did to address issue #17 ("Improve horse facts ux — boring and repeating"):

Research findings

I searched for a horse facts API and found none exists that's reliable and horse-specific — horsefacts.org is a parked page, and the only free, key-less options are generic trivia (catfact.ninja, uselessfacts.jsph.pl). So I kept the curated list as the resilient default and made an API an opt-in layer, consistent with how RSS feeds already work in this bot.

The fix (3 parts)

  1. No more repeats — facts now come from a shuffle bag (FactDeck): the bot cycles through the entire list before any fact repeats. The state is persisted to fact-deck.json, so restarts/redeploys never repeat a just-shown fact. This is the direct fix for "repeating."

  2. ~70 verified facts (up from ~30) — keeps things fresh for months.

  3. Optional API sourceIRC_FACTS_API_URL tries a JSON endpoint ({"fact"}/{"text"}) first each day and silently falls back to the deck on any failure, so the channel always gets a fact and a flaky API can never break the feature.

Quality

All CI gates pass: deno fmt, deno lint, deno check, 176 tests (≈30 new), and Fallow dead-code analysis (clean). The unused pickRandomFact was removed rather than suppressed, and the new modules (fact-store.ts) follow the existing store/persistence conventions.


View action run | Model: zai/glm-5.2 (thinking: max) | Time: 18m 17s | Tokens: 3.2M | Pi SDK v0.81.1 | Action v2.26.0-develop (develop @ 4387e26)

Let me look at the remaining test files and check whether I have network access to research APIs.Now let me check whether I have network access to research available horse facts APIs.I have network access. Let me research horse facts APIs more and read the storage modules to match conventions.I have network access and have completed my research. Let me verify one more API shape (the JSON response formats) so my implementation is accurate.My research is complete. Here's what I found: - **No reliable, dedicated horse facts API exists.** `horsefacts.org` is a parked landing page (404 on `/api`). - The closest free, no-key APIs are *generic* trivia: `catfact.ninja/fact` → `{"fact":"..."}` and `uselessfacts.jsph.pl/.../random` → `{"text":"..."}` — neither is horse-specific. - Most other fact APIs require API keys. Given the bot's resilience-first design, I'll implement: (1) a **non-repeating shuffle-deck** so facts stop repeating, (2) a **much larger curated list**, and (3) an **optional API-backed source** with graceful fallback to the curated deck. Let me build it.Now the persistence store for the deck state:Now let me add the config for the optional API source and store path:Now let me update `main.ts` to wire the deck and optional API provider:Now let me add the `createFactProvider` helper to `main.ts`. Let me place it near `broadcastFact`:Now let me update the existing `broadcastFact` test for the new async signature:Now let me update `facts_test.ts` — the data-integrity tests still apply, and I'll add thorough tests for `shuffle`, `FactDeck`, and `fetchApiFact`:Now let me create the `fact-store_test.ts`:Now let me add config tests for the new `facts` settings:Now let me update the `.env.example` and README. First let me check the current Deno version and run the tests:`FactsSettings` lives in `config.ts`, not `facts.ts`. Let me fix the import in `main.ts`:The reconciliation test over-drew (crossing a cycle boundary). Let me fix it to assert only what reconciliation actually guarantees:All 180 tests pass. Now let me run the linter, formatter, type check, and Fallow static analysis:Type check passes. Let me fix the unused import:Lint is clean. Now let me run Fallow (dead-code analysis) and verify formatting:Fallow found issues. Since `HORSE_FACTS` is now actually consumed by `main.ts`, its suppression is stale. And `pickRandomFact` is now dead code (superseded by `FactDeck`). Let me clean these up: remove `pickRandomFact` and fix the suppressions.Now remove the `pickRandomFact` import and its tests from `facts_test.ts`:Let me re-read the current state of the test file to make precise edits:The trailing prose in the suppression comment confused Fallow's parser. Let me use the exact recognized form:Fallow is clean. Now let me run the full test suite once more to confirm everything passes:All tests pass. Now let me update the documentation — `.env.example` and the README:I accidentally removed the feeds section. Let me restore it after the new facts section:Now let me update the README — the config table and the "Daily horse facts" section:Now let me update the "Daily horse facts" section in the README to describe the new behavior:Let me update the project structure section in the README to mention the new file:Now let me run the full check suite once more (fmt, lint, check, test, fallow) to make sure everything is green:The README needs formatting. Let me apply fmt:Everything is green. Let me do a final review of the complete diff:Let me verify the new untracked files are included and review the final config wiring:Let me verify the final main.ts wiring:All wiring looks correct. Let me run one final comprehensive check to confirm a clean state before creating the PR:All green: fmt, lint, type-check, 176 tests, and Fallow dead-code analysis all pass. Now let me create the PR:PR #18 created. Here's a summary of what I did to address issue #17 ("Improve horse facts ux — boring and repeating"): ## Research findings I searched for a horse facts API and found **none exists** that's reliable and horse-specific — `horsefacts.org` is a parked page, and the only free, key-less options are *generic* trivia (`catfact.ninja`, `uselessfacts.jsph.pl`). So I kept the curated list as the resilient default and made an API an **opt-in** layer, consistent with how RSS feeds already work in this bot. ## The fix (3 parts) 1. **No more repeats** — facts now come from a **shuffle bag** (`FactDeck`): the bot cycles through the *entire* list before any fact repeats. The state is persisted to `fact-deck.json`, so restarts/redeploys never repeat a just-shown fact. This is the direct fix for "repeating." 2. **~70 verified facts** (up from ~30) — keeps things fresh for months. 3. **Optional API source** — `IRC_FACTS_API_URL` tries a JSON endpoint (`{"fact"}`/`{"text"}`) first each day and silently falls back to the deck on any failure, so the channel always gets a fact and a flaky API can never break the feature. ## Quality All CI gates pass: `deno fmt`, `deno lint`, `deno check`, **176 tests** (≈30 new), and Fallow dead-code analysis (clean). The unused `pickRandomFact` was removed rather than suppressed, and the new modules (`fact-store.ts`) follow the existing store/persistence conventions. --- [View action run](https://forge.l3x.in/alex/irc-greeter-bot/actions/runs/72) | Model: zai/glm-5.2 (thinking: max) | Time: 18m 17s | Tokens: 3.2M | Pi SDK v0.81.1 | Action v2.26.0-develop (develop @ 4387e26)
alex closed this issue 2026-07-30 11:31:13 +00:00
Sign in to join this conversation.
No labels
dependencies
No milestone
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
alex/irc-greeter-bot#17
No description provided.