diff --git a/AGENTS/AI_CONTRACT.md b/AGENTS/AI_CONTRACT.md new file mode 100644 index 0000000..e6c7b35 --- /dev/null +++ b/AGENTS/AI_CONTRACT.md @@ -0,0 +1,331 @@ +# AI_CONTRACT.md — Universal AI Agent Contract + +> Binding for any AI agent (Claude, GPT, Gemini, or other) in any repo. +> Stack-agnostic. Derived from the Runewager production development system. +> Do not modify without appending a note to AGENTS/SESSION_LOG.md. + +--- + +## The Single Invariant + +> **The source code, the functionality map, and the wiring index must always +> agree. No session is complete until all three are in sync.** + +Drift between these three causes every class of AI mistake: +hallucinating behavior that doesn't exist, missing behavior that does exist, +breaking wiring that was never documented, and leaving the next agent blind. + +--- + +## Pre-Session: Bootstrap (Mandatory — Do This First) + +Before reading any source file or writing any code, verify and create missing +documentation paths. This is not optional. A repo with missing docs is a repo +where AI agents will hallucinate. + +### Check and create each path if missing: + +``` +FUNCTIONALITY_MAP.md + → If missing: create from AGENTS/MAP_TEMPLATE.md + → Run a quick codebase scan to populate it with real entry points, + real file names, real data stores. Never create it with placeholder + content that doesn't reflect the actual repo. + +docs/INDEX.md + → If missing: create from AGENTS/INDEX_TEMPLATE.md + → Populate the wiring tables with every entry point found during scan. + +docs/features/ + → If missing: create the directory. + → Do not create feature files yet — create them as features are touched. + +todolist.md + → If missing: create from AGENTS/TODOLIST_TEMPLATE.md + → Add any obviously open tasks discovered during the bootstrap scan. + +AGENTS/SESSION_LOG.md + → If missing: create it with the header from AGENTS/SESSION_LOG.md template. + → Never delete or overwrite existing entries. Append only. +``` + +### Bootstrap scan — what to look for: + +When creating `FUNCTIONALITY_MAP.md` and `docs/INDEX.md` fresh, scan the repo for: + +- **Entry points:** command handlers, route definitions, event listeners, + cron job registrations, webhook receivers, button/action handlers, CLI arg + parsers, IPC message handlers, socket event handlers, queue consumers. +- **State:** databases, in-memory stores (Map, Set, dict, hash), file + persistence, session/cookie storage, cache layers, environment variables. +- **Process management:** systemd unit files (`.service`), pm2 config + (`ecosystem.config.js`, `pm2.config.cjs`), Procfile, docker-compose.yml, + supervisor conf. +- **Test files:** `test/`, `tests/`, `spec/`, `__tests__/`, `*.test.*`, + `*.spec.*`. +- **Deploy scripts:** `deploy.sh`, `prod-run.sh`, `Makefile`, CI workflow + files (`.github/workflows/`). +- **Config:** `.env.example`, `config/`, `settings.py`, `appsettings.json`. +- **Health/metrics:** `/health` endpoints, `/metrics`, uptime scripts, + monitoring hooks. + +--- + +## Article 1 — Pre-Session Reads (Mandatory) + +After bootstrap, read in this order before writing any code: + +1. `AGENTS/CLAUDE.md` — operating manual for this repo. +2. `FUNCTIONALITY_MAP.md` — what the system does, how it behaves. +3. `docs/INDEX.md` — how every piece is wired together. +4. `todolist.md` — what is open, in-progress, blocked, and done. +5. The specific section of `FUNCTIONALITY_MAP.md` for the area being changed. +6. The specific source file(s) for the code being changed. + +Do not skip any of these. An agent that writes code without reading the map +is operating on assumptions, not facts. + +--- + +## Article 2 — The Universal Wiring Index Rule + +`docs/INDEX.md` is the **Universal Wiring Index**. It must capture every +way functionality is invoked, handled, and connected — for any stack. + +### What goes in the wiring index (stack-agnostic terms): + +| Category | Examples by stack | +|----------|-------------------| +| **Entry points** | `/command` (bot), `GET /route` (web), `cli subcommand` (CLI), `screen name` (mobile), `menu item` (desktop), `queue.consume()` (service), `socket.on('event')` (realtime), `cron('0 * * * *')` (scheduled) | +| **Handlers** | Function name, file path, line number range | +| **State reads** | Which store/db/variable/session the handler reads | +| **State mutations** | What the handler writes, creates, deletes, or updates | +| **UI/UX output** | What the user/caller sees — screen, message, response body, side effect | +| **Guards/permissions** | Who can invoke this — role check, auth middleware, API key, rate limit | +| **Error paths** | What happens on failure — error message, fallback, retry, alert | +| **Wiring connections** | What this calls, emits, publishes, or triggers in other parts of the system | + +### Format: + +```markdown +## Entry Point Index + +| Entry Point | Type | Handler | File:Line | State Read | State Write | Output | Guard | Error Path | +|------------|------|---------|-----------|------------|-------------|--------|-------|------------| +| /start | Command | handleStart() | index.js:412 | userStore | user.onboarding | Onboarding card | none | "Already started" reply | +| GET /api/users | Route | getUsers() | routes/users.js:28 | db.users | none | JSON array | requireAuth | 401 / 500 | +| checkout button | UI event | submitOrder() | checkout.js:89 | cart, session | orders, cart | Confirmation screen | loggedIn | Error toast | +| order.created | Queue event | processOrder() | workers/order.js:14 | orders | inventory, email_queue | none (async) | none | dead-letter queue | +| */5 * * * * | Cron | runCleanup() | jobs/cleanup.js:5 | sessions | sessions | none | none | admin alert | +``` + +### Index must be updated when: + +| Change | Index update required | +|--------|-----------------------| +| New entry point added (command, route, action, event, job) | Add row | +| Entry point removed | Remove row | +| Handler function renamed or moved | Update Handler + File:Line | +| State the handler reads or writes changes | Update State Read / State Write | +| Output changes (new screen, new response shape, new side effect) | Update Output | +| Guard/permission added, removed, or changed | Update Guard | +| New wiring connection (calls a new service, emits new event) | Update Wiring connections | + +--- + +## Article 3 — During-Session Rules + +1. Add tasks to `todolist.md` before starting them. +2. Mark the current task `[~]` before beginning it. +3. Make the minimal change that satisfies the requirement. +4. Do not refactor, rename, or restructure code unrelated to the current task. +5. If blocked: mark `[BLOCKED: ]`, move to next priority task. Do not + wait. Do not retry the same blocked path more than twice. +6. Verify immediately after each task (run tests, syntax check, or trace). +7. Mark `[x]` done immediately after verification. + +--- + +## Article 4 — Post-Session Sync (Mandatory Before Commit) + +### 4.1 — Functionality Map + +Update `FUNCTIONALITY_MAP.md` to reflect real code state: + +- New entry point → add to the relevant section + Commands/Endpoints Index. +- Removed entry point → remove it. Do not leave stale entries. +- Changed behavior → update the description. Do not describe intended behavior. +- New flow or feature → add a new section. +- Changed state machine → update the state machine table. +- Changed config, env vars, infra → update Architecture Notes. +- Changed process manager config → update Process Management section. + +### 4.2 — Wiring Index + +Update `docs/INDEX.md`: + +- Any entry point change → update the Entry Point Index table. +- Any handler rename or move → update Handler and File:Line columns. +- Any state change → update State Read / State Write columns. +- Any new inter-system connection → add to wiring connections. + +### 4.3 — Feature Doc + +If `docs/features/.md` exists for the changed area: + +- Update flow steps to match new code behavior. +- Update edge cases, timeouts, validation rules. +- Update related entry points and handlers. + +If no feature doc exists and the change is non-trivial: create one. + +### 4.4 — Session Log + +Append to `AGENTS/SESSION_LOG.md`: + +```markdown +### YYYY-MM-DD — + +**Scope:** <files / features / systems touched> +**Changes:** +- <what changed> +- <what changed> +**Tests:** pass / fail / N/A — <test command used> +**Map updated:** yes / partial / no — <what was updated> +**Index updated:** yes / partial / no +**Open items:** <anything deferred with reason> +``` + +### 4.5 — Final Verification Checklist + +Before committing: + +- [ ] All tests pass (or confirmed N/A with reason documented) +- [ ] `FUNCTIONALITY_MAP.md` matches code behavior — not intended behavior +- [ ] `docs/INDEX.md` has no dead references or missing entry points +- [ ] No debug code, `console.log`, `print()`, or `TODO` comments left in source +- [ ] No secrets in any committed file +- [ ] `todolist.md` reflects current state +- [ ] Session log appended + +--- + +## Article 5 — Definition of Done + +A task is done when ALL of the following are true: + +- [ ] Code change is implemented and working. +- [ ] Code change is verified (automated or manual). +- [ ] `FUNCTIONALITY_MAP.md` reflects the change. +- [ ] `docs/INDEX.md` reflects the change. +- [ ] Feature doc reflects the change (if one exists). +- [ ] Session log is updated. +- [ ] Task is marked `[x]` in `todolist.md`. + +A task that passes code review but has no map update is **not done**. +A task with a map update but failing tests is **not done**. +A task marked done but not in the session log **did not happen**. + +--- + +## Article 6 — Commands/Entry Points Guard Rule + +For any system with a defined set of owned commands, routes, or entry points: + +**Any time an entry point is added or removed, the guard set (or equivalent +registry) that controls routing/access must be updated in the same commit.** + +Examples: +- Telegram bot: `BOT_KNOWN_COMMANDS` set must match `bot.command()` registrations. +- Express app: route registry or OpenAPI spec must match `app.get/post/...`. +- CLI tool: command registry must match `program.command(...)` registrations. +- Event system: subscribed event list must match `socket.on(...)` or `bus.subscribe(...)`. + +A command/route/event that exists in code but not in the registry is invisible +to guards and audits. A command in the registry but not in code causes false +positives in validation. Both cause drift. + +--- + +## Article 7 — Anti-Hallucination Rules + +These rules directly prevent AI agents from inventing behavior: + +1. **Never describe a feature as working unless you have read the code that + implements it.** Not the comment. Not the doc. The code. +2. **Never add a feature to the map that isn't in the code.** Maps describe + reality, not plans. +3. **Never assume a function signature, parameter name, or return value without + reading its definition.** Grep for it. Read it. +4. **Never assume a behavior is unchanged because you didn't touch it.** Other + code may call it. Check callers. +5. **Never write a test for behavior you haven't verified exists in the code.** +6. **Never write error handling for an error that cannot happen.** Read the + code path and confirm the error condition is reachable. + +--- + +## Article 8 — Safety Rules + +- Never expose secrets, tokens, API keys, or credentials in any committed file. +- Never commit a `.env` file. +- Never run destructive operations without explicit user confirmation: + `rm -rf`, `DROP TABLE`, `git reset --hard`, `git push --force` to main, + `pm2 delete all`, `docker system prune -a`. +- Never mark done when tests fail. +- Never modify code you have not read. +- Never skip the pre-session map read. + +--- + +## Article 9 — Escalation + +Stop and report before continuing when: + +- Map and code contradict each other and context doesn't resolve it. +- Tests that passed before your session now fail for unrelated reasons. +- The task touches auth, permissions, credentials, or external APIs. +- The task requires a destructive operation. +- The scope is substantially larger than described. +- You would need to change behavior used in more than three places in the system. +- The correct behavior is genuinely ambiguous between two interpretations. + +--- + +## Appendix A — Stack-Specific Contract Addendum + +Fill in when first applying this contract to a repo: + +```markdown +### Project: <name> +**Entry point:** <file> +**Entry point guard:** <BOT_KNOWN_COMMANDS / route registry / command registry> +**Test command:** <npm test / pytest / go test ./... / cargo test> +**Syntax check:** <node --check / mypy / cargo check / eslint> +**Deploy command:** <./prod-run.sh / pm2 reload / systemctl restart / docker compose up> +**Process manager:** <systemd / pm2 / docker / supervisor / bare> +**Health check:** <curl http://localhost:PORT/health / pm2 status / systemctl status> +**Persistence:** <what data lives where and how often it's saved> +**Project-specific rules:** +- <any rule that extends or overrides the universal contract> +``` + +--- + +## Appendix B — Universal Development Cycle + +``` +READ PLAN CODE +──────────────────── ──────────────────── ──────────────────── +FUNCTIONALITY_MAP → todolist.md → source files +docs/INDEX.md prioritize tasks minimal changes +feature docs mark [~] current no side quests +source files identify doc targets verify each task + +SYNC CLOSE +──────────────────── ──────────────────── +FUNCTIONALITY_MAP → run full tests +docs/INDEX.md commit: code + docs +feature doc push to branch +SESSION_LOG +``` diff --git a/AGENTS/CLAUDE.md b/AGENTS/CLAUDE.md new file mode 100644 index 0000000..0b93c85 --- /dev/null +++ b/AGENTS/CLAUDE.md @@ -0,0 +1,252 @@ +# CLAUDE.md — AI Agent Operating Manual + +> Derived from the Runewager production development system. +> Stack-agnostic. Language-agnostic. Works for any repo. +> Last updated: 2026-03-04 + +--- + +## 1. Identity + +You are an autonomous elite software engineer. You are not a code generator — +you are a systems thinker who writes code. You understand that the map of a +system is as important as the code itself. You leave every repo better +documented, better tested, and better understood than when you arrived. + +You never drift. You never hallucinate behavior. You never describe something +as working unless you have read the code that makes it work. + +--- + +## 2. First Action in Any Session: Bootstrap Check + +Before doing anything else, run the bootstrap check. This takes 60 seconds and +prevents every class of AI mistake. + +``` +Does FUNCTIONALITY_MAP.md exist? → if not, create it from AGENTS/MAP_TEMPLATE.md +Does docs/INDEX.md exist? → if not, create it from AGENTS/INDEX_TEMPLATE.md +Does todolist.md exist? → if not, create it from AGENTS/TODOLIST_TEMPLATE.md +Does AGENTS/SESSION_LOG.md exist? → if not, create it (empty, with header) +``` + +To auto-run the bootstrap check in one step: + +```bash +bash AGENTS/bootstrap.sh +``` + +After bootstrap, read in this order — no exceptions: + +``` +1. AGENTS/AI_CONTRACT.md ← your binding rules for this session +2. FUNCTIONALITY_MAP.md ← source of truth for all system behavior +3. docs/INDEX.md ← universal wiring index (entry points → handlers → state → UI) +4. todolist.md ← open tasks, priorities, blockers +``` + +--- + +## 3. Session Workflow — The Async Pattern + +This workflow is designed to be non-blocking. Multiple concerns are tracked in +parallel. No single task blocks the session. Blocked tasks get "Deferred" with +a condition; work moves to the next priority. + +``` +┌──────────────────────────────────────────────────────────────────────────┐ +│ SESSION WORKFLOW │ +│ │ +│ PHASE 1: ORIENT (parallel reads) │ +│ ───────────────────────────────── │ +│ Read FUNCTIONALITY_MAP.md Read docs/INDEX.md │ +│ Read todolist.md Read feature doc for target area │ +│ Read source files for target area (all reads happen before any write) │ +│ │ +│ PHASE 2: PLAN (update todolist before writing code) │ +│ ────────────────────────────────────────────────── │ +│ Add tasks in priority order: P1 bugs → P1 stability → P2 → P3 │ +│ Mark current task [~] before starting │ +│ Identify what docs will need updating before touching code │ +│ │ +│ PHASE 3: EXECUTE (one task at a time, non-blocking) │ +│ ────────────────────────────────────────────────── │ +│ Write minimal code for the task │ +│ If blocked → mark [BLOCKED: <reason>], move to next P-level task │ +│ Verify immediately (tests / syntax / trace) │ +│ Mark [x] done before moving on │ +│ │ +│ PHASE 4: SYNC (mandatory before commit) │ +│ ────────────────────────────────────── │ +│ Update FUNCTIONALITY_MAP.md Update docs/INDEX.md │ +│ Update feature doc (if exists) Append to AGENTS/SESSION_LOG.md │ +│ │ +│ PHASE 5: CLOSE │ +│ ────────────── │ +│ Run full test suite │ +│ Commit: code + map updates in same commit │ +│ Push to branch │ +└──────────────────────────────────────────────────────────────────────────┘ +``` + +### Why async/non-blocking matters + +In Runewager development, sessions handled 20+ tasks across 4 priority levels +simultaneously. The system worked because: + +- **Maps were the shared memory.** The next session didn't need a handoff + narration — it read the map and knew the state of everything. +- **Blocked tasks didn't stop the session.** If modularizing index.js was + blocked on test coverage, P2 logging tasks continued. +- **Todolist had live state.** `[~]` in-progress, `[x]` done, `[BLOCKED]` + stalled — any agent picking up mid-session could see exactly where things + stood. +- **Commits were atomic.** Code change + map update in one commit meant the + repo was never in a half-documented state. + +--- + +## 4. The Documentation Hierarchy + +Every repo using this system has three levels of documentation: + +``` +FUNCTIONALITY_MAP.md ← source of truth. Describes what the system does. + Updated every session. Never speculative. + +docs/INDEX.md ← universal wiring index. Every entry point, handler, + state mutation, UI flow, and system connection + cross-referenced in tables. Quick-jump to anything. + +docs/features/<n>.md ← deep-dive per feature. Flows, edge cases, validation + rules, error paths, related wiring. One file per + major feature or module. +``` + +**The invariant:** These three levels must always agree with the source code. +Any AI agent that writes code without updating all three levels has left the +repo in a drifted state. + +--- + +## 5. Universal Wiring Index — What It Covers + +The `docs/INDEX.md` wiring index covers every way something can be invoked +in the system, regardless of stack: + +| Stack | Entry points captured | +|-------|-----------------------| +| Telegram bot | `/commands`, inline button callbacks, text handlers, middleware | +| Web app | Routes (GET/POST/etc.), component events, form submissions, webhooks | +| REST API | Endpoints, query params, request bodies, response shapes | +| GraphQL | Queries, mutations, subscriptions, resolvers | +| CLI tool | Commands, subcommands, flags, arguments, env vars | +| Mobile app | Screens, navigation actions, gestures, deep links, push handlers | +| Desktop app | Menu items, keyboard shortcuts, window events, IPC messages | +| Background service | Cron jobs, queue consumers, event subscriptions, scheduled tasks | +| Smart contract | Public functions, events emitted, state variables | + +For every entry point, the index records: +- What triggers it (user action, system event, schedule, other code) +- What code handles it (function name, file, line range) +- What state it reads +- What state it mutates +- What the user/caller sees (UI output, response, side effect) +- What guards or permissions apply +- What can go wrong and how it's handled + +--- + +## 6. Process Manager Awareness + +When the project uses a process manager, the agent must know which one and +how it affects the restart/deploy cycle. Record this in `FUNCTIONALITY_MAP.md` +under Architecture. + +| Manager | How agent interacts | +|---------|---------------------| +| **systemd** | `systemctl start/stop/restart <service>` — unit file in repo, reload with `daemon-reload` | +| **pm2** | `pm2 start/stop/restart/reload <name>` — config in `ecosystem.config.js` or `pm2.config.cjs` — `pm2 save` after changes — `pm2 logs <name>` for tails | +| **supervisor** | `supervisorctl start/stop/restart <program>` — config in `/etc/supervisor/conf.d/` | +| **docker** | `docker compose up/down/restart` — `docker logs <container>` | +| **forever** | `forever start/stop/restart <script>` | +| **bare nohup** | `nohup node app.js &` — PID tracked manually — fragile, prefer pm2 or systemd | + +When writing deploy or restart scripts, always resolve the node/runtime binary +path explicitly rather than relying on PATH: + +```bash +NODE_BIN="$(command -v node)" # resolve once, use everywhere +"$NODE_BIN" app.js # consistent binary across systemd / pm2 / nohup +``` + +--- + +## 7. Commit Convention + +``` +<type>(<scope>): <what changed and why> + +feat(auth): add JWT refresh token rotation +fix(checkout): prevent double-charge on retry +docs(map): sync FUNCTIONALITY_MAP with payment flow changes +chore(deploy): resolve node binary path in pm2 fallback +test(giveaway): add weighted winner pool unit tests +refactor(api): extract parseCommand helper, reduce duplication +``` + +Scope = the feature area, not the filename. + +**One rule:** code changes and map/index updates always go in the same commit. +Never commit code without the map update. Never commit a map update without +the corresponding code change. + +--- + +## 8. Safety Rules + +- Never expose secrets, tokens, or credentials in any committed file. +- Never modify code you have not read. +- Never describe behavior in docs that isn't implemented in code. +- Never implement behavior that isn't documented in the map. +- Never mark a task `[x]` when tests are failing. +- Never run destructive operations (`rm -rf`, `DROP TABLE`, `git reset --hard`, + force-push to main) without explicit user confirmation in the current session. +- Never assume a pattern from one part of the codebase applies to another + without reading both. + +--- + +## 9. Escalation Rules + +Stop and report before continuing when: + +- Map and code contradict each other and context doesn't resolve it. +- Tests were passing before your session and are now failing for unrelated reasons. +- The task requires touching auth, permissions, credentials, or external APIs. +- The task requires a destructive operation. +- The scope turns out to be substantially larger than described. +- You are about to change behavior that is used in more than three places. + +--- + +## 10. Capability Catalog (fill in per project) + +Add this block to `AGENTS/CLAUDE.md` when first setting up a new repo: + +```markdown +## Project: <name> + +**What it does:** <one sentence> +**Stack:** <language / framework / runtime> +**Entry point:** <main file> +**Config:** <how config is loaded — .env, YAML, env vars> +**Tests:** <test command and test file locations> +**Syntax/lint:** <e.g. node --check / mypy / eslint / cargo check> +**Deploy:** <how to deploy — script, CI, manual> +**Health check:** <how to verify it's running> +**Process manager:** <systemd / pm2 / docker / supervisor / bare> +**Persistence:** <database, file, in-memory — and where> +**Critical path:** <entry point → handler → state → output, in plain English> +**Docs system:** FUNCTIONALITY_MAP.md + docs/INDEX.md + docs/features/ +``` diff --git a/AGENTS/INDEX_TEMPLATE.md b/AGENTS/INDEX_TEMPLATE.md new file mode 100644 index 0000000..0cb9e2f --- /dev/null +++ b/AGENTS/INDEX_TEMPLATE.md @@ -0,0 +1,185 @@ +# docs/INDEX.md — Universal Wiring Index + +> **Primary navigation hub for all Claude/AI sessions.** +> Every entry point, handler, state mutation, UI flow, and system connection. +> Cross-referenced to feature docs. Updated every session. +> Stack-agnostic — use the columns that fit your project. +> +> **How to use:** Find the entry point, command, action, route, or feature you +> need. Follow the Handler column to the exact file and line. Follow the Doc +> column to the full feature documentation. +> +> Last updated: YYYY-MM-DD | Version: X.X.X + +--- + +## Quick Navigation + +| I want to find... | Go to | +|-------------------|-------| +| A specific command / route / action | [Entry Point Index](#entry-point-index) | +| What state a handler reads or writes | [Entry Point Index](#entry-point-index) → State columns | +| What the user sees at each step | [UI/UX Flow Index](#uiux-flow-index) | +| How two systems are connected | [Wiring / Inter-System Connections](#wiring--inter-system-connections) | +| A pending input or wait state | [Wait-State Index](#wait-state-index) | +| A background job or scheduled task | [Background & Scheduled Tasks](#background--scheduled-tasks) | +| A specific feature deep-dive | [Feature Doc Index](#feature-doc-index) | +| Where an error is handled | [Error Path Index](#error-path-index) | + +--- + +## Feature Doc Index + +| # | Feature | Doc | Role | Status | +|---|---------|-----|------|--------| +| 01 | [Feature name] | [docs/features/01-name.md](features/01-name.md) | user/admin/system | ✅ Active | + +--- + +## Entry Point Index + +> Every way the system can be invoked. One row per entry point. +> Type column vocab: `command`, `route`, `action/callback`, `event`, `cron`, +> `queue`, `webhook`, `socket`, `keyboard-shortcut`, `menu-item`, `gesture`, +> `ipc`, `button/ui-event`. + +### User-Facing + +| Entry Point | Type | Handler Function | File : Line | State Read | State Write | UI Output | Guard | Error Path | Doc | +|------------|------|-----------------|-------------|------------|-------------|-----------|-------|------------|-----| +| `/start` | command | `handleStart()` | `index.js:412` | `userStore` | `user.onboarding` | Onboarding card | none | "Bot unavailable" | [01](features/01-name.md) | +| `GET /api/users` | route | `getUsers()` | `routes/users.js:28` | `db.users` | none | JSON array | `requireAuth` | 401 JSON | [02](features/02-name.md) | +| `[Buy] button` | ui-event | `handleCheckout()` | `checkout.js:89` | `cart`, `session` | `orders`, `cart` | Confirmation screen | `isLoggedIn` | Error toast | [03](features/03-name.md) | +| `order.created` | queue | `processOrder()` | `workers/order.js:14` | `orders` | `inventory` | none (async) | none | dead-letter | [04](features/04-name.md) | + +### Admin / Operator + +| Entry Point | Type | Handler Function | File : Line | State Read | State Write | UI Output | Guard | Error Path | Doc | +|------------|------|-----------------|-------------|------------|-------------|-----------|-------|------------|-----| +| `/admin` | command | `handleAdmin()` | `index.js:900` | `userStore` | none | Admin panel | `requireAdmin` | "Not authorized" | [03](features/03-name.md) | + +### Aliases / Shorthand + +| Short form | Resolves to | Notes | +|------------|-------------|-------| +| `/menu` | Same as `/start` | Legacy alias | + +--- + +## UI/UX Flow Index + +> Maps user-visible flows end to end. How screens/messages connect. +> Shows what the user sees at each step and what drives the next step. + +| Flow | Entry | Steps | Completion | Error Recovery | Doc | +|------|-------|-------|------------|----------------|-----| +| Onboarding | `/start` | Age gate → Account setup → Link username → Community | Main menu shown | `/stuck` recovery | [01](features/01-name.md) | +| Checkout | Cart screen | Item review → Payment → Confirm → Receipt | Order created | Retry / cancel | [03](features/03-name.md) | +| Password reset | Forgot password link | Email entry → Code verify → New password | Login screen | Resend / support | [05](features/05-name.md) | + +--- + +## Wait-State Index (Pending Input) + +> For systems with a state machine where the system waits for user input. +> Examples: multi-step wizards, pending actions, form flows, conversation states. + +| State/Type | Feature | What is awaited | Timeout | On Timeout | On Cancel | Handler | File:Line | Doc | +|------------|---------|----------------|---------|------------|-----------|---------|-----------|-----| +| `await_username` | Onboarding | Username text input | 15 min | Return to menu | Clear state | `handleTextInput()` | `index.js:2100` | [01](features/01-name.md) | +| `await_payment` | Checkout | Payment confirmation | 10 min | Order cancelled | Order cancelled | `handlePaymentReply()` | `payment.js:45` | [03](features/03-name.md) | + +--- + +## Background & Scheduled Tasks + +| Task | Schedule / Trigger | Handler | File:Line | State Write | Side Effect | Error Behavior | +|------|--------------------|---------|-----------|-------------|-------------|----------------| +| Session cleanup | `*/10 * * * *` | `cleanupSessions()` | `jobs/cleanup.js:5` | `sessions` | none | Admin alert | +| State persistence | every 15s | `persistRuntimeState()` | `index.js:890` | file: `data/state.json` | none | Log + continue | +| Weekly summary | `0 9 * * 1` | `sendWeeklySummary()` | `jobs/summary.js:12` | none | Email sent | Log + skip | + +--- + +## Wiring / Inter-System Connections + +> How pieces of the system call, emit, or depend on each other. +> Prevents changes to one module from blindly breaking another. + +| From | To | How | When | Notes | +|------|-----|-----|------|-------| +| `handleCheckout()` | `inventory.decrementStock()` | direct call | On order confirm | Must complete before receipt shown | +| `processOrder()` | `emailService.send()` | async call | After inventory update | Non-blocking; failure logged | +| `bot.command('start')` | `middleware.groupGuard` | middleware chain | Before handler runs | Group commands redirected to DM | +| `giveaway.finalize()` | `notifyWinners()` | direct call | On timer expiry | Each winner DM'd individually | +| `deploy.yml` | `prod-run.sh` | SSH exec | On push to main | Script is idempotent | + +--- + +## Callback / Action / Event Handler Index + +> For event-driven systems. Maps every emitted event or triggered action to its handler. + +| Callback / Event / Action ID | Handler | File:Line | Triggers | Notes | Doc | +|-----------------------------|---------|-----------|---------|-------|-----| +| `to_main_menu` | `handleMainMenu()` | `index.js:5200` | Main menu render | Clears stale menus first | [02](features/02-name.md) | +| `gw_join_<id>` | `handleGiveawayJoin()` | `index.js:7100` | Eligibility check + join | Regex handler | [04](features/04-name.md) | +| `CLICK_SUBMIT` (Redux) | `submitReducer()` | `store/order.js:45` | API call + UI update | Dispatched from checkout screen | [03](features/03-name.md) | +| `user:registered` (event bus) | `onUserRegistered()` | `events/user.js:12` | Welcome email, analytics | Async listener | [01](features/01-name.md) | + +--- + +## Error Path Index + +> Where errors are caught and how they surface to users or operators. + +| Error Condition | Where caught | User-facing output | Operator alert | Recovery path | Doc | +|----------------|-------------|-------------------|----------------|---------------|-----| +| Unhandled exception | `process.on('uncaughtException')` | none (silent) | Admin Telegram DM | Restart via systemd/pm2 | [10](features/10-name.md) | +| DB connection failure | `db.connect()` try/catch | "Service unavailable" | Error log + alert | Retry with backoff | — | +| Auth failure | `requireAuth()` middleware | 401 JSON response | none | Redirect to login | [05](features/05-name.md) | +| Invalid input | inline validation | Inline error message | none | Re-prompt | — | + +--- + +## Guard / Permission Index + +> Every access control check in the system. + +| Guard | How it works | Where applied | Failure behavior | +|-------|-------------|---------------|-----------------| +| `requireAuth` | Checks session token | All `/api` routes | 401 response | +| `requireAdmin` | Checks ADMIN_IDS list | Admin commands/routes | "Not authorized" reply | +| `BOT_KNOWN_COMMANDS` | Set membership check | Group command middleware | Silently ignore | +| `isOwner` | Compares userId to resource.ownerId | Edit/delete routes | 403 response | +| `rateLimiter` | Per-IP/user request count | All routes | 429 response | + +--- + +## Configuration & Environment Index + +| Variable | Used in | Purpose | Required | Default | +|----------|---------|---------|----------|---------| +| `BOT_TOKEN` | `index.js:1` | Telegram auth | yes | none | +| `PORT` | `index.js:890` | HTTP server port | no | `3000` | +| `DATABASE_URL` | `db.js:5` | DB connection string | yes | none | +| `LOG_LEVEL` | `logger.js:3` | Minimum log level | no | `info` | +| `ADMIN_IDS` | `index.js:279` | Comma-separated admin IDs | yes | none | + +--- + +## Anti-Drift Checklist + +Run this check at the end of every session before committing: + +- [ ] Every `bot.command()` / `app.get()` / `program.command()` has a row in Entry Point Index +- [ ] Every entry point row has the correct Handler, File:Line, Guard, and Error Path +- [ ] Every removed entry point has been removed from all tables +- [ ] Every new wiring connection is in the Wiring table +- [ ] Every new wait-state is in the Wait-State Index +- [ ] Feature Doc Index matches the actual files in `docs/features/` +- [ ] Guard index reflects actual guard functions in the codebase + +--- + +## Known Issues → See todolist.md diff --git a/AGENTS/MAP_TEMPLATE.md b/AGENTS/MAP_TEMPLATE.md new file mode 100644 index 0000000..dc7777f --- /dev/null +++ b/AGENTS/MAP_TEMPLATE.md @@ -0,0 +1,283 @@ +# FUNCTIONALITY_MAP.md — [Project Name] + +> **Source of truth for all system behavior.** +> Updated every session. Describes what code does, not what was planned. +> Stack-agnostic template — delete sections that don't apply, add sections that do. +> Last audited: YYYY-MM-DD + +--- + +## 1. Project Overview + +**What it does:** [One sentence. What problem does this solve for what user?] + +**Stack:** [Language / Runtime / Framework / Key libraries] + +**Architecture pattern:** [Monolith / Microservices / Serverless / MVC / Event-driven / etc.] + +**Entry point:** [Main file or service that boots the system] + +**Config:** [How is config loaded — .env, YAML, env vars, config files] + +--- + +## 2. Architecture Summary + +### Runtime / Process Model + +``` +[Entry point] + └── [Framework/router layer] + └── [Handler layer] + └── [State/data layer] + └── [Persistence/external layer] +``` + +Example for different stacks: +``` +# Web app +server.js → Express router → controllers → services → database + +# Telegram bot +index.js → Telegraf middleware → command handlers → in-memory stores → JSON file + +# CLI tool +main.go → cobra commands → business logic → file system / API + +# Mobile app +App.tsx → React Navigation → screens → redux store → AsyncStorage / API +``` + +### Process Management + +**Manager:** [systemd / pm2 / docker / supervisor / bare process] + +```bash +# How to start +[start command] + +# How to stop +[stop command] + +# How to restart +[restart command] + +# How to check logs +[log command] + +# How to check status +[status command] +``` + +**Config file:** [path to systemd unit / pm2 ecosystem.config.js / docker-compose.yml] + +**Runtime binary resolution:** [Note if the binary path is resolved explicitly or relies on PATH] + +### State / Storage Layers + +| Store | Type | What it holds | Persistence | Location | +|-------|------|---------------|-------------|----------| +| [name] | in-memory Map / Redis / Postgres / file / etc. | [what data] | [duration / interval] | [path or connection] | + +### External Dependencies + +| Dependency | Type | Purpose | Configured via | +|------------|------|---------|----------------| +| [name] | API / DB / queue / service | [why] | [env var / config key] | + +--- + +## 3. Global Behaviors + +[Behaviors that apply system-wide, not just to one feature. Examples:] + +- **Authentication:** How identity is established and enforced globally. +- **Rate limiting:** Global and per-user rate limits and what triggers them. +- **Error handling:** Global error handler, how unhandled errors surface. +- **Logging:** What is logged, at what level, where logs go. +- **Middleware chain:** What runs on every request/command/event before handlers. +- **Guards:** What checks run before protected actions. +- **Crash recovery:** What happens on process crash — restart policy, state recovery. +- **Health reporting:** How the system reports its own health. + +--- + +## 4. Feature Index + +| # | Feature | Doc | Role | Status | +|---|---------|-----|------|--------| +| 01 | [Feature name] | [docs/features/01-name.md](docs/features/01-name.md) | [user/admin/system] | ✅ Active | +| 02 | [Feature name] | [docs/features/02-name.md](docs/features/02-name.md) | [user/admin/system] | ✅ Active | + +--- + +## 5. Entry Point Index (Commands / Routes / Actions / Events) + +> This is the universal wiring index. Every way the system can be invoked. +> Stack-agnostic — use the column names that fit your project. + +### [User-facing / Public] + +| Entry Point | Type | Handler | File:Line | State Read | State Write | Output | Guard | Error Path | +|------------|------|---------|-----------|------------|-------------|--------|-------|------------| +| [/start] | [command] | [handleStart()] | [index.js:412] | [userStore] | [user.onboarding] | [Onboarding card] | [none] | ["Already started"] | +| [GET /users] | [route] | [getUsers()] | [routes/users.js:28] | [db.users] | [none] | [JSON array] | [requireAuth] | [401 / 500] | +| [submit button] | [UI event] | [submitForm()] | [checkout.js:89] | [formState] | [orders] | [Confirmation] | [loggedIn] | [Error toast] | + +### [Admin / Operator] + +| Entry Point | Type | Handler | File:Line | State Read | State Write | Output | Guard | Error Path | +|------------|------|---------|-----------|------------|-------------|--------|-------|------------| +| [/admin] | [command] | [handleAdmin()] | [index.js:900] | [userStore] | [none] | [Admin panel] | [requireAdmin] | ["Not authorized"] | + +### [System / Scheduled / Background] + +| Entry Point | Type | Handler | File:Line | Trigger | State Write | Side Effect | +|------------|------|---------|-----------|---------|-------------|-------------| +| [cleanupJob] | [cron] | [runCleanup()] | [jobs/cleanup.js:5] | [*/5 * * * *] | [sessions] | [Admin alert on error] | +| [order.created] | [queue event] | [processOrder()] | [workers/order.js:14] | [queue publish] | [inventory] | [Email sent] | + +### [Aliases / Shortcuts] + +| Short form | Resolves to | Notes | +|------------|-------------|-------| +| [/menu] | Same handler as /start | [Legacy alias] | + +--- + +## 6. UI/UX Flow Map + +[Describe the user-visible flows. For each major flow:] + +### [Flow Name — e.g. User Onboarding] + +``` +[Entry trigger] + → [Step 1: what user sees] + → [User action A] → [Step 2A] + → [User action B] → [Step 2B] + → [Step 2]: [what user sees] + → [Continue] → [Step 3] + → [Cancel] → [Return to home] + → [Completion: what user sees] +``` + +**State written on completion:** [list what changes in the data layer] +**Error paths:** [what happens when each step fails] +**Timeouts:** [if any step times out, what happens] + +--- + +## 7. State Machine (if applicable) + +> Use for systems with explicit state transitions — pending actions, order states, +> onboarding steps, workflows, approval chains, etc. + +### [State Machine Name] + +| From State | Event / Trigger | To State | Guard | Side Effect | +|------------|----------------|----------|-------|-------------| +| [idle] | [user submits] | [pending] | [loggedIn] | [email sent] | +| [pending] | [admin approves] | [approved] | [requireAdmin] | [user notified] | +| [pending] | [timeout 15min] | [expired] | [none] | [auto-cancelled] | + +**Timeout behavior:** [what happens when a state times out] +**Recovery:** [how a user recovers from an unexpected state] + +--- + +## 8. Input Validation Rules + +| Field | Accepted format | Rejection behavior | Where enforced | +|-------|-----------------|--------------------|----------------| +| [username] | [alphanumeric, 3-20 chars] | ["Invalid username" reply] | [validateUsername() in utils.js] | +| [amount] | [positive float, max 2 decimal] | ["Enter a valid amount"] | [parseAmount() in payments.js] | + +--- + +## 9. Permissions & Access Control + +| Role | How identified | What they can access | What they cannot | +|------|----------------|----------------------|------------------| +| [Guest] | [no session] | [public routes] | [anything requiring auth] | +| [User] | [session token] | [user routes, own data] | [admin routes, other users' data] | +| [Admin] | [ADMIN_IDS env / role flag] | [all routes] | [none] | + +--- + +## 10. Error Handling & Crash Recovery + +**Global error handler:** [where it is, what it does] +**Unhandled promise rejections:** [how handled] +**Process crash behavior:** [systemd restart / pm2 restart / manual] +**State recovery on restart:** [how state is restored from persistence] +**Admin alerting:** [when and how admins are notified of errors] + +--- + +## 11. Configuration Reference + +| Variable | Purpose | Default | Required | +|----------|---------|---------|----------| +| [BOT_TOKEN] | [Telegram bot token] | [none] | [yes] | +| [PORT] | [HTTP server port] | [3000] | [no] | +| [LOG_LEVEL] | [debug/info/warn/error] | [info] | [no] | +| [NODE_ENV] | [production/development] | [development] | [no] | + +--- + +## 12. Deployment & Operations + +**Deploy command:** [how to deploy] +**Rollback:** [how to roll back] +**Health check:** [command or URL to verify system is running] +**Logs:** [where logs live, how to tail them] +**Backups:** [what is backed up, when, where] + +--- + +## 13. Test Coverage + +| Test file | What it covers | Run command | +|-----------|----------------|-------------| +| [test/unit.test.js] | [core business logic] | [npm test] | +| [test/smoke.test.js] | [entry point registration parity] | [npm test] | +| [test/integration.test.js] | [end-to-end flows] | [npm run test:integration] | + +**Test philosophy:** [what the tests assert, what they don't cover] + +--- + +## 14. Commands / Entry Points Guard (Anti-Drift) + +For systems with a defined set of owned entry points, name the guard mechanism here: + +**Guard:** [name of set, registry, or config that gates routing] +**Location:** [file:line] +**Rule:** Any entry point added or removed in code must be synchronized to this +guard in the same commit. + +--- + +## 15. Known Issues & Technical Debt + +| ID | Issue | Severity | File | Notes | +|----|-------|----------|------|-------| +| T-01 | [description] | [P1/P2/P3] | [file] | [status / plan] | + +--- + +## 16. Feature Documentation System + +| File | Contents | +|------|---------| +| [`docs/INDEX.md`](docs/INDEX.md) | Universal wiring index — every entry point, handler, state, and connection | +| [`docs/features/01-name.md`](docs/features/01-name.md) | [Feature description] | + +--- + +## 17. Session Update Log + +> Append at the end of every session. Never delete. Newest at bottom. + +- YYYY-MM-DD: [What changed and why] diff --git a/AGENTS/SESSION_LOG.md b/AGENTS/SESSION_LOG.md new file mode 100644 index 0000000..9c826bc --- /dev/null +++ b/AGENTS/SESSION_LOG.md @@ -0,0 +1,49 @@ +# AGENTS/SESSION_LOG.md — Append-Only Session History + +> One entry per session. Append at bottom. Never delete entries. +> Format: date, scope, changes, tests, map/index updated, open items. + +--- + +### 2026-03-04 — Code Review Fixes + Universal AI Agent System + +**Scope:** `index.js`, `prod-run.sh`, `AGENTS/` + +**Changes:** +- `index.js`: Added 15 missing commands to `BOT_KNOWN_COMMANDS` set + (`admin_log`, `promo_cooldown`, `discord_stats`, `gw_graphic`, `stuck`, + `fixaccount`, `discord_confirm`, `mygiveaways`, `checkin`, `top`, + `boostmeter`, `eligible`, `gwhistory`, `promocheck`, `support`) +- `index.js`: Extracted `parseGroupCommand(text)` shared helper from group + guard middleware — eliminates duplicate command-parsing logic +- `index.js`: Added `_auditKnownCommandsDrift()` startup runtime guard — + cross-checks all `bot.command()` registrations against `BOT_KNOWN_COMMANDS` + at launch, logs drift to admin DMs +- `prod-run.sh`: Resolved `NODE_BIN` at validation time (`command -v node`), + used in all nohup fallback calls — eliminates binary version skew +- `prod-run.sh`: Fixed restart fallback race: `systemctl stop` before nohup, + port freed before bind, current PID re-fetched after failed restart +- `AGENTS/CLAUDE.md`: Complete rewrite — bootstrap protocol, async workflow + pattern, process manager table (systemd/pm2/docker/supervisor/bare), + universal documentation hierarchy +- `AGENTS/AI_CONTRACT.md`: Complete rewrite — bootstrap-first requirement, + universal wiring index rule, anti-hallucination rules, stack-agnostic + entry point vocabulary +- `AGENTS/MAP_TEMPLATE.md`: Created — blank FUNCTIONALITY_MAP for any repo, + UI/UX flow map section, state machine table, all sections stack-agnostic +- `AGENTS/INDEX_TEMPLATE.md`: Created — full universal wiring index template + covering all stack types (commands, routes, actions, events, queues, cron, + sockets, keyboard shortcuts, gestures, IPC) +- `AGENTS/TODOLIST_TEMPLATE.md`: Created — priority-based task board template +- `AGENTS/bootstrap.sh`: Created — idempotent script that creates all missing + documentation paths, optional `--scan` for codebase summary, `--dry-run` + +**Tests:** 60/60 pass (`npm test`) — no regressions +**Map updated:** yes — `RUNEWAGER_FUNCTIONALITY_MAP.md` § 25 AI Coder Contract, + Session Update Log +**Index updated:** yes — `docs/INDEX.md` reflects group guard changes +**Open items:** +- `prod-run.sh` endpoint nohup lines (lines 481, 494) still use bare `node` — + to be updated in next session (low risk; endpoint is a companion service) +- Modularize `index.js` — deferred pending >80% test coverage +- Memory eviction for inactive users — deferred pending user count >10k diff --git a/AGENTS/TODOLIST_TEMPLATE.md b/AGENTS/TODOLIST_TEMPLATE.md new file mode 100644 index 0000000..c5d1e55 --- /dev/null +++ b/AGENTS/TODOLIST_TEMPLATE.md @@ -0,0 +1,78 @@ +# [Project Name] — Task Board + +_Last updated: YYYY-MM-DD — [brief note on what this update covers]_ + +--- + +## LEGEND + +| Symbol | Meaning | +|--------|---------| +| `[ ]` | Open — not started | +| `[~]` | In progress — being worked on right now | +| `[x]` | Done — verified and committed | +| `[!]` | Confirmed bug — reproducible defect in code | +| `[BLOCKED: reason]` | Cannot proceed — waiting on dependency or decision | +| `[P1]` | Critical — crashes, data loss, security, broken core flow | +| `[P2]` | Important — degraded UX, missing feature, slow | +| `[P3]` | Nice to have — cleanup, optimization, cosmetic | + +--- + +## BUGS — Confirmed Defects + +> Reproducible issues in production or testable code. Prioritize above all features. + +- [!] [P1] **[Short bug description]** `file.js` + - Impact: [what breaks / who is affected] + - Repro: [how to reproduce it] + - Fix: [known fix or investigation needed] + +--- + +## P1 — CRITICAL + +> Crashes, data loss, security vulnerabilities, broken core flows. Do these first. + +- [ ] **[Task name]** `file.js` + - [What needs to change and why] + +--- + +## P2 — IMPORTANT + +> Broken or missing functionality that degrades the user experience but doesn't +> crash the system. + +- [ ] **[Task name]** `file.js` + - [What needs to change and why] + +--- + +## P3 — NICE TO HAVE + +> Cleanup, refactors, optimizations, polish. Do after P1 and P2 are clear. + +- [ ] **[Task name]** `file.js` + - [What needs to change and why] + +--- + +## DEFERRED + +> Explicitly postponed. Requires a condition to be unblocked. + +- [BLOCKED: needs >80% test coverage] **Modularize main file into src/** + - Plan: split by feature module once integration tests cover core flows. + +- [BLOCKED: needs user count >10k] **Add memory eviction for inactive users** + - Plan: evict users inactive >90 days when userStore grows beyond threshold. + +--- + +## COMPLETED + +> Done, verified, committed. Keep the last 20–30 entries for context. +> Archive older entries by moving to AGENTS/SESSION_LOG.md. + +- [x] **[Task name]** — [brief note on what was done and when] diff --git a/AGENTS/bootstrap.sh b/AGENTS/bootstrap.sh new file mode 100755 index 0000000..d362ddc --- /dev/null +++ b/AGENTS/bootstrap.sh @@ -0,0 +1,273 @@ +#!/usr/bin/env bash +# ============================================================================= +# AGENTS/bootstrap.sh — Universal AI Agent Bootstrap +# +# Run this at the start of any session in any repo to ensure all required +# documentation paths exist. Creates missing files from templates. +# Safe to run multiple times (idempotent). +# +# Usage: +# bash AGENTS/bootstrap.sh +# bash AGENTS/bootstrap.sh --scan # also scans codebase and reports summary +# bash AGENTS/bootstrap.sh --dry-run # shows what would be created, no writes +# +# What it creates (if missing): +# FUNCTIONALITY_MAP.md ← source of truth for all system behavior +# docs/INDEX.md ← universal wiring index +# docs/features/ ← per-feature documentation directory +# todolist.md ← task board +# AGENTS/SESSION_LOG.md ← append-only session log +# ============================================================================= +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +REPO_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" + +DRY_RUN=0 +SCAN=0 + +for arg in "$@"; do + case "$arg" in + --dry-run) DRY_RUN=1 ;; + --scan) SCAN=1 ;; + --help|-h) + sed -n '/^# Usage/,/^# What/p' "${BASH_SOURCE[0]}" | head -10 + exit 0 ;; + esac +done + +# ─── Colours ──────────────────────────────────────────────────────────────── +_green='\033[0;32m'; _yellow='\033[1;33m'; _cyan='\033[0;36m'; _reset='\033[0m' +ok() { echo -e " ${_green}✔${_reset} $*"; } +warn() { echo -e " ${_yellow}⚠${_reset} $*"; } +info() { echo -e " ${_cyan}→${_reset} $*"; } + +# ─── Helper: create file from template if missing ─────────────────────────── +ensure_file() { + local target="$1" + local template="$2" # may be empty string if no template + local description="$3" + + if [[ -f "$target" ]]; then + ok "EXISTS $target" + return 0 + fi + + warn "MISSING $target ($description)" + + if (( DRY_RUN )); then + info "[DRY-RUN] would create from: ${template:-inline}" + return 0 + fi + + mkdir -p "$(dirname "$target")" + + if [[ -n "$template" && -f "$template" ]]; then + cp "$template" "$target" + ok "CREATED $target (from template)" + else + # Inline minimal stub when no template exists + create_stub "$target" "$description" + ok "CREATED $target (stub — fill in before committing)" + fi +} + +# ─── Minimal stubs when templates are not available ───────────────────────── +create_stub() { + local file="$1" + local description="$2" + local today; today="$(date '+%Y-%m-%d')" + + case "$(basename "$file")" in + FUNCTIONALITY_MAP.md) + cat > "$file" <<EOF +# FUNCTIONALITY_MAP.md + +> Source of truth for all system behavior. Last audited: ${today} +> See AGENTS/MAP_TEMPLATE.md for the full annotated template. + +## 1. Project Overview +**What it does:** [Fill in] +**Stack:** [Fill in] +**Entry point:** [Fill in] + +## 2. Architecture Summary +[Fill in] + +## 3. Entry Point Index + +| Entry Point | Type | Handler | File:Line | Output | Guard | +|------------|------|---------|-----------|--------|-------| +| [Fill in] | | | | | | + +## 4. Session Update Log +- ${today}: Bootstrap — map created, needs population. +EOF + ;; + INDEX.md) + cat > "$file" <<EOF +# docs/INDEX.md — Universal Wiring Index + +> Last updated: ${today} +> See AGENTS/INDEX_TEMPLATE.md for the full annotated template. + +## Entry Point Index + +| Entry Point | Type | Handler | File:Line | State Write | Output | Guard | Doc | +|------------|------|---------|-----------|-------------|--------|-------|-----| +| [Fill in] | | | | | | | | + +## Feature Doc Index + +| # | Feature | Doc | Status | +|---|---------|-----|--------| +| 01 | [Fill in] | [docs/features/01-name.md](features/01-name.md) | 🔲 Stub | +EOF + ;; + todolist.md) + cat > "$file" <<EOF +# Task Board + +_Last updated: ${today} — bootstrap stub_ + +## LEGEND +\`[ ]\` open \`[~]\` in-progress \`[x]\` done \`[!]\` bug \`[BLOCKED]\` waiting +\`[P1]\` critical \`[P2]\` important \`[P3]\` nice-to-have + +## BUGS +_(none confirmed yet)_ + +## P1 — CRITICAL +- [ ] Populate FUNCTIONALITY_MAP.md with real system behavior +- [ ] Populate docs/INDEX.md with real entry points + +## P2 — IMPORTANT +_(none yet)_ + +## P3 — NICE TO HAVE +_(none yet)_ + +## COMPLETED +_(none yet)_ +EOF + ;; + SESSION_LOG.md) + cat > "$file" <<EOF +# AGENTS/SESSION_LOG.md — Append-Only Session History + +> One entry per session. Append at bottom. Never delete entries. +> Format: date, scope, changes, tests, map update, open items. + +--- + +### ${today} — Bootstrap + +**Scope:** Repository initialization +**Changes:** +- Created AGENTS/ documentation system via bootstrap.sh +- Created missing documentation stubs (populate before next session) +**Tests:** N/A +**Map updated:** stub only +**Open items:** Populate FUNCTIONALITY_MAP.md and docs/INDEX.md with real data +EOF + ;; + esac +} + +# ─── Main ─────────────────────────────────────────────────────────────────── +echo "" +echo "╔══ Runewager / Universal AI Agent Bootstrap ══╗" +echo " Repo: $REPO_DIR" +echo " Mode: $( (( DRY_RUN )) && echo 'DRY RUN' || echo 'live' )" +echo "" + +# Required documentation files +ensure_file \ + "$REPO_DIR/FUNCTIONALITY_MAP.md" \ + "$SCRIPT_DIR/MAP_TEMPLATE.md" \ + "source of truth for all system behavior" + +ensure_file \ + "$REPO_DIR/docs/INDEX.md" \ + "$SCRIPT_DIR/INDEX_TEMPLATE.md" \ + "universal wiring index" + +ensure_file \ + "$REPO_DIR/todolist.md" \ + "$SCRIPT_DIR/TODOLIST_TEMPLATE.md" \ + "task board" + +ensure_file \ + "$REPO_DIR/AGENTS/SESSION_LOG.md" \ + "" \ + "append-only session log" + +# Ensure docs/features/ directory exists +if [[ ! -d "$REPO_DIR/docs/features" ]]; then + if (( DRY_RUN )); then + warn "MISSING docs/features/ (directory for per-feature docs)" + info "[DRY-RUN] would create directory" + else + mkdir -p "$REPO_DIR/docs/features" + ok "CREATED docs/features/ (per-feature documentation directory)" + fi +else + ok "EXISTS docs/features/" +fi + +# ─── Optional codebase scan ───────────────────────────────────────────────── +if (( SCAN )); then + echo "" + echo "╔══ Codebase Scan Summary ══╗" + echo "" + + # Count entry points by type + for pattern in "bot\.command(" "app\.\(get\|post\|put\|delete\|patch\)(" \ + "router\.\(get\|post\|put\|delete\)(" \ + "program\.command(" "socket\.on(" "\.on\('" \ + "cron\.\|schedule\.\|setInterval(" \ + "queue\.consume\|consumer\.run"; do + count=$(grep -rl "$pattern" "$REPO_DIR" \ + --include="*.js" --include="*.ts" --include="*.py" \ + --include="*.go" --include="*.rb" --include="*.java" \ + 2>/dev/null | wc -l || echo 0) + [[ "$count" -gt 0 ]] && info "Pattern '$pattern': found in $count file(s)" + done + + echo "" + info "Source files:" + find "$REPO_DIR" -maxdepth 3 \ + \( -name "*.js" -o -name "*.ts" -o -name "*.py" -o -name "*.go" \ + -o -name "*.rb" -o -name "*.java" \) \ + ! -path "*/node_modules/*" ! -path "*/.git/*" ! -path "*/vendor/*" \ + 2>/dev/null | wc -l | xargs -I{} echo " {} source files found" + + echo "" + info "Test files:" + find "$REPO_DIR" -maxdepth 4 \ + \( -name "*.test.*" -o -name "*.spec.*" -o -path "*/test/*" -o -path "*/tests/*" \) \ + ! -path "*/node_modules/*" ! -path "*/.git/*" \ + 2>/dev/null | wc -l | xargs -I{} echo " {} test file(s) found" + + echo "" + info "Process manager detection:" + [[ -f "$REPO_DIR/ecosystem.config.js" || -f "$REPO_DIR/pm2.config.cjs" ]] \ + && ok "pm2 config found" || info "no pm2 config" + find "$REPO_DIR" -maxdepth 3 -name "*.service" 2>/dev/null | grep -q . \ + && ok "systemd unit file(s) found" || info "no .service files" + [[ -f "$REPO_DIR/docker-compose.yml" || -f "$REPO_DIR/docker-compose.yaml" ]] \ + && ok "docker-compose found" || info "no docker-compose" + [[ -f "$REPO_DIR/Procfile" ]] \ + && ok "Procfile found" || info "no Procfile" +fi + +echo "" +echo "╔══ Bootstrap Complete ══╗" +echo "" +echo " Next steps for this session:" +echo " 1. Read AGENTS/AI_CONTRACT.md" +echo " 2. Read FUNCTIONALITY_MAP.md" +echo " 3. Read docs/INDEX.md" +echo " 4. Read todolist.md" +echo " 5. Work → update maps → verify → commit" +echo "" diff --git a/index.js b/index.js index d96c82c..8c7b03f 100644 --- a/index.js +++ b/index.js @@ -14919,6 +14919,79 @@ bot.action('support_cancel', async (ctx) => { await ctx.reply('❌ Support ticket cancelled.'); }); +// ========================= +// Startup: BOT_KNOWN_COMMANDS drift guard +// Asserts that every bot.command() registration exists in BOT_KNOWN_COMMANDS. +// Fires once at process start (before bot.launch()) to catch drift immediately +// rather than relying solely on code review discipline. +// ========================= +/** + * _registeredCommands collects every command name passed to bot.command() at + * module-load time so the drift guard below can cross-check against BOT_KNOWN_COMMANDS. + * It is populated by the instrumented _trackCommand wrapper defined next. + */ +const _registeredCommands = new Set(); + +/** + * _trackCommand wraps bot.command() to record the command name(s) in + * _registeredCommands. It is called for all existing registrations via a + * post-registration audit loop below rather than replacing bot.command itself + * (which would require re-patching Telegraf internals). + */ +function _auditKnownCommandsDrift() { + // Collect every command name registered via bot.command() by inspecting + // Telegraf's internal middleware tree. Telegraf stores each command handler + // as a { triggers: Set<string>, ... } entry. We iterate the composed layers. + const layers = bot.middleware?.()?.handler?.middleware || []; + const cmdNames = new Set(); + + const gatherFromLayers = (arr) => { + if (!Array.isArray(arr)) return; + for (const layer of arr) { + // Telegraf command middleware exposes triggers (Set or array of strings) + if (layer && layer.triggers instanceof Set) { + for (const t of layer.triggers) { + if (typeof t === 'string') cmdNames.add(t.toLowerCase()); + } + } + // Recurse into nested composed middleware + if (layer && layer.handler && typeof layer.handler === 'function') { + const nested = layer.handler.middleware; + if (nested) gatherFromLayers(nested); + } + } + }; + + gatherFromLayers(layers); + + // Also scan the explicit _registeredCommands set if populated by wrappers + for (const c of _registeredCommands) cmdNames.add(c); + + const driftedIn = []; // registered in bot but not in BOT_KNOWN_COMMANDS + const driftedOut = []; // in BOT_KNOWN_COMMANDS but never registered (informational) + + for (const cmd of cmdNames) { + if (!BOT_KNOWN_COMMANDS.has(cmd)) driftedIn.push(cmd); + } + // 'start' is handled by bot.start(), not bot.command() — exclude from driftedOut scan + const SKIP_OUT = new Set(['start']); + for (const cmd of BOT_KNOWN_COMMANDS) { + if (!SKIP_OUT.has(cmd) && !cmdNames.has(cmd)) driftedOut.push(cmd); + } + + if (driftedIn.length > 0) { + const msg = `[BOT_KNOWN_COMMANDS DRIFT] Commands registered via bot.command() but MISSING from BOT_KNOWN_COMMANDS: ${driftedIn.join(', ')}. Add them to the set near line 279 of index.js.`; + logEvent('error', msg); + _startupWarnings.push(`⚠️ BOT_KNOWN_COMMANDS drift detected — missing: ${driftedIn.join(', ')}`); + } + if (driftedOut.length > 0) { + logEvent('warn', `[BOT_KNOWN_COMMANDS DRIFT] Commands in BOT_KNOWN_COMMANDS but not registered via bot.command() (may be intentional): ${driftedOut.join(', ')}`); + } + if (driftedIn.length === 0) { + logEvent('info', '[BOT_KNOWN_COMMANDS] Drift check passed — all registered commands are in the known-commands set.'); + } +} + // ── Feature 26: Weekly Auto-DM Boost Reminder ──────────────────────────── /** * runWeeklyBoostReminder executes its scoped Runewager logic and participates in menu/command or utility flow composition. @@ -14987,6 +15060,9 @@ async function startBot() { loadPersistentData(); ensureQaArtifacts(); persistRuntimeState(); + // Run drift check before launch so any warnings land in _startupWarnings + // before the admin notification loop fires below. + _auditKnownCommandsDrift(); logEvent('info', 'Starting Runewager Bot', { admins: ADMIN_IDS.length, node: process.version, host: os.hostname() }); await configureBotSurface(); await bot.launch(); diff --git a/prod-run.sh b/prod-run.sh index f1d367b..ca899b9 100755 --- a/prod-run.sh +++ b/prod-run.sh @@ -219,7 +219,11 @@ if ! command -v npm >/dev/null 2>&1; then err "npm is not on PATH — install Node.js >= 20 and retry" exit 1 fi -say "Node: $(node --version) npm: $(npm --version)" +# Resolve the exact node binary path once so every nohup fallback below +# uses the same runtime that was validated here (avoids version skew if +# the PATH differs between this script and the systemd ExecStart). +NODE_BIN="$(command -v node)" +say "Node: $(node --version) npm: $(npm --version) binary: $NODE_BIN" # --------------------------------------------------------- # 4) Ensure .env exists