Some checks failed
tests / Unit tests (Node 22) (push) Failing after 2m13s
Expands the unit test suite from 320 to 380 tests (+60) and adds a
Gitea Actions CI workflow. Closes all six follow-up recommendations
from the test-architecture validation report.
New tests (tests/unit/):
- ollamaClient.test.ts — Ollama SDK wrapper, options passthrough
- litellmClient.test.ts — OpenAI SDK wrapper, model fallback
- personaLoader.test.ts — Zod validation + cache invalidation
- foundryReward.test.ts — Tool plugin: lookup, errors, partial grants
- xpAwarder.test.ts — Bulk XP awards + per-player skip reasons
- redisErrorPath.test.ts — Singleton error handler does not crash
- messageRouterRunLLMTurn.test.ts — 18 cases for the runtime heart:
narrative-only path, tool dispatch, filter correction, retry loop
guard, missed-skill-check heuristic, typing indicator interval,
LLM error fallback, archive on resolve.
Coverage (line %):
- harness/litellmClient.ts 0 → 100
- harness/ollamaClient.ts 0 → 100
- harness/tools/foundryReward.ts 0 → 100
- session/xpAwarder.ts 0 → 100
- persona/loader.ts 0 → 100
- db/redis.ts 0 → 100
- bot/handlers/messageRouter.ts 0 → 39.86 (runLLMTurn now covered)
Tooling:
- package.json: + test:coverage, test:watch scripts
- devDep: @vitest/coverage-v8@^3.1.0
- tests/README.md: conventions, anti-patterns, template map
- .gitignore: exclude coverage/
- .gitea/workflows/test.yml: Node 22, npm cache, tsc --noEmit gate
Documentation (from earlier /bmad-document-project run, now committed):
- docs/index.md
- docs/project-overview.md
- docs/architecture.md
- docs/deployment-guide.md
- docs/api-contracts.md
- docs/data-models.md
- docs/source-tree-analysis.md
- docs/component-inventory.md
- docs/development-guide.md
- _bmad-output/test-artifacts/automate-validation-report.md
Co-Authored-By: Claude <noreply@anthropic.com>
7.5 KiB
7.5 KiB
Component Inventory
Reusable and feature-specific components in the Mardonar Encounter Engine. Generated 2026-06-19.
Discord Components
Slash commands (reusable across all guilds)
| Component | File | Reusable? | Notes |
|---|---|---|---|
/dndname |
src/bot/commands/dndname.ts |
Yes | Character name gate. Universal. |
/encounter |
src/bot/commands/encounter.ts |
Yes | Encounter lifecycle. Spec-scoped via start <spec>. |
/character |
src/bot/commands/character.ts |
Yes | Full character profile + Foundry link. |
/roll |
src/bot/commands/roll.ts |
Yes | Manual roll outside encounter. |
/actions |
src/bot/commands/actions.ts |
Yes | In-character action shortcuts. |
/xp |
src/bot/commands/xp.ts |
Yes | XP grant. |
/encounters |
src/bot/commands/encounters.ts |
Yes | Search via GraphMCP. |
/turn |
src/bot/commands/turn.ts |
Yes | Turn management. |
Embeds (pure builders, reusable)
| Embed | File | Caller |
|---|---|---|
| PlayerGate | src/bot/embeds/playerGate.ts |
messageRouter (unregistered player) |
| Suspense + SkillCheck | src/bot/embeds/skillCheck.ts |
tools/skillCheckEmit.ts |
| Resolution | src/bot/embeds/resolution.ts |
tools/encounterResolve.ts |
| EncounterDiscovery | src/bot/embeds/encounterDiscovery.ts |
/encounters |
| LoreAnswer | src/bot/embeds/loreAnswer.ts |
mentionHandler |
Event handlers (reusable, sidecar logic)
| Handler | File | Trigger | Side effects |
|---|---|---|---|
handleMessage |
handlers/messageRouter.ts |
messageCreate in encounter thread |
Gates, debounce, LLM call, tool dispatch |
handleMention |
handlers/mentionHandler.ts |
messageCreate @Zalram |
Lore search + persona reply |
handleRollInteraction |
handlers/rollHandler.ts |
Button / modal submit | Resolves skill check, schedules LLM turn |
scheduleEncounterLLMTurn |
handlers/messageRouter.ts |
Internal | Debounce → LLM turn |
scheduleLLMTurn |
handlers/generationQueue.ts |
Internal | Debounce timer |
isBurstCapped / sendDropNotice |
handlers/queueCap.ts |
Pre-append check | Drops + notifies |
registerScheduled / drainPending / upgradeToProcessing / upgradeToComplete |
handlers/reactionManager.ts |
Per-message | 👀 reaction lifecycle |
filterLLMResponse / detectMissedSkillCheck |
handlers/responseFilter.ts |
Post-LLM | Injects [FILTER CORRECTION] |
LLM Harness Components
Tool plugins (registered globally, filtered per-encounter)
| Plugin | File | Per-encounter filter | Side effects |
|---|---|---|---|
skill_check_emit |
harness/tools/skillCheckEmit.ts |
Spec tools: |
Posts suspense + dice embed; updates pendingSkillCheck |
encounter_resolve |
harness/tools/encounterResolve.ts |
Spec tools: |
Writes summary, archives thread |
context_recall |
harness/tools/contextRecall.ts |
Spec tools: |
Returns canonical facts from resolvedContext |
goal_register |
harness/tools/goalRegister.ts |
Spec tools: |
Adds dynamic goal (per prd.md) |
foundry_lookup |
harness/tools/foundryLookup.ts |
Spec tools: |
Live VTT actor data |
foundry_reward |
harness/tools/foundryReward.ts |
Spec tools: |
XP/item grant to VTT actor |
LLM clients
| Client | File | Role |
|---|---|---|
llmClient (router) |
harness/llmClient.ts |
LiteLLM primary, Ollama fallback |
litellmClient |
harness/litellmClient.ts |
OpenAI-compatible HTTP |
ollamaClient |
harness/ollamaClient.ts |
Native ollama npm + direct HTTP |
Pipeline components
| Component | File | Role |
|---|---|---|
buildSystemPrompt |
harness/promptBuilder.ts |
10-block XML system prompt |
assembleContext |
harness/contextAssembler.ts |
System + pinned + trimmed sliding |
parseToolCall |
harness/toolParser.ts |
3-pattern tool block extractor |
buildToolManifest |
harness/toolDispatcher.ts |
Per-encounter tool contract section |
dispatchTool |
harness/toolDispatcher.ts |
Active-set validation + dispatch |
getActiveTools |
harness/toolRegistry.ts |
Per-encounter filter (or all if unset) |
registerTool |
harness/toolRegistry.ts |
Side-effect registration at module load |
Session / Data Components
| Component | File | Backend | Surface |
|---|---|---|---|
sessionManager |
session/sessionManager.ts |
Redis (TTL 12h) | create, get, update, addMessage, delete, getGuildThreadIds |
playerRegistry |
session/playerRegistry.ts |
Redis | (guildId, discordId) → Player |
characterRegistry |
session/characterRegistry.ts |
Redis | Character profile (pronouns, Foundry UUID, etc.) |
encounterLog |
session/encounterLog.ts |
Filesystem | tally.json + per-encounter .txt in data/summaries/ |
xpAwarder |
session/xpAwarder.ts |
VTT relay | XP grant |
redis singleton |
db/redis.ts |
ioredis | Lazy connect, 3 retries |
loadSpec |
spec/loader.ts |
YAML + Zod | EncounterSpecSchema.parse |
loadPersona |
persona/loader.ts |
YAML | @Zalram persona |
GraphMCP Components
| Component | File | RPC method | Used by |
|---|---|---|---|
queryAsNPC |
graphmcp/client.ts |
query_as_npc |
NPC memory injection at session start |
semanticSearch |
graphmcp/client.ts |
semantic_search |
@mention lore search |
logEncounter |
graphmcp/client.ts |
log_encounter |
Encounter resolve (writes graph node) |
listEncounters |
graphmcp/client.ts |
list_encounters |
/encounters list |
searchEncounters |
graphmcp/client.ts |
search_encounters |
/encounters search |
getEncounter |
graphmcp/client.ts |
get_encounter |
/encounters get |
formatNPCMemory |
graphmcp/client.ts |
(local) | Render NPCQueryResult as system-prompt text |
publishToGraphMCP |
graphmcp/ingest.ts |
(Redis stream raw.messages) |
Fire-and-forget per encounter message |
vocabularyResolver |
graphmcp/vocabularyResolver.ts |
graphmcp | randomizable: lookup |
loreResolver |
graphmcp/loreResolver.ts |
graphmcp | /encounter generate helper |
VTT Components
| Component | File | Role |
|---|---|---|
foundryClient |
vtt/foundryClient.ts |
HTTP client, live actor data + formatters |
relaySession.ensureRelaySession |
vtt/relaySession.ts |
Auto-spin-up headless session on relay failure |
isRelayDown |
vtt/relaySession.ts |
Network-failure classifier |
actorCache (in tools/skillCheckEmit.ts) |
in-file | 30s in-memory cache for actor details |
Type system (shared)
| Type | File | Purpose |
|---|---|---|
EncounterSpec |
types/index.ts |
Spec shape (note: diverged slightly from Zod schema — see architecture.md §9) |
NpcPersona |
types/index.ts |
NPC definition |
EncounterGoal / EncounterGoals |
types/index.ts |
Primary/secondary goals |
SessionState |
types/index.ts |
Full session shape |
ChatMessage |
types/index.ts |
History turn (with pinned flag) |
HeldMessage |
types/index.ts |
Pre-registration messages |
ToolCallBlock / LLMResponse |
types/index.ts |
LLM tool surface |
ToolName |
types/index.ts |
Discriminated union of valid tools |
*Args per tool |
types/index.ts |
Per-tool arg types |
NpcNode / EncounterNode / EncounterEventNode |
types/index.ts |
Neo4j graph node types |
CONTEXT_BUDGET (const) |
types/index.ts |
Hard token budget zones |
Config & logging
| Component | File | Role |
|---|---|---|
config (singleton) |
config.ts |
Zod-validated env (Discord, Redis, LiteLLM, Ollama, GraphMCP, VTT, persona, logging) |
log (pino wrapper) |
lib/logger.ts |
Structured logging with pino-pretty in dev |