Properties
category: spec tags: [quota, disk-usage, plugin, plan] last_updated: 2026-03-17 confidence: high
Per-Wiki Disk Usage Caps Plan
Quota enforcement code already exists in resolver.py (50MB limit, write rejection) but reads from robot.db where disk_usage_bytes is always 0. This plan wires up real measurements.
Architecture
- Measurement:
du -sbon entire wiki directory (repo + wiki.db + FAISS index) - Storage: New
statstable in per-wikiwiki.db(not robot.db) — resolver already operates per-wiki-DB - Update timing: Page count on every save/delete (via otterwiki plugin hook). Disk usage via cron only (15-min interval, acceptable lag).
- Enforcement: Existing resolver code — reads stats from
wiki.dbafter DB swap, strips WRITE permission or returns 413 for API requests.
Components
1. stats table in wiki.db
CREATE TABLE IF NOT EXISTS stats ( name VARCHAR(64) PRIMARY KEY, value TEXT, updated_at DATETIME );
Keys: page_count, disk_usage_bytes. Seeded in _init_wiki_db().
2. New plugin: otterwiki-wikistats
Follows otterwiki-api pattern. Hooks: page_saved, page_deleted → update page_count via storage.list(). Disk usage left to cron. Must use _state["storage"] dict (not self.storage) for multi-tenant correctness — resolver patches this in _swap_storage().
3. Resolver changes
- Add
_get_wiki_stats(wiki_dir)— readsstatstable fromwiki.db - Move quota check to after
_swap_database()— read real disk_usage fromwiki.dbwith fallback torobot.db - Add
otterwiki_wikistats._state["storage"]patch in_swap_storage() - Seed
statstable in_init_wiki_db()
4. Cron backstop update
Update wiki-quota.sh.j2 to write to each wiki's wiki.db stats table (primary) AND keep updating robot.db for the dashboard API.
User Experience
- API/MCP: HTTP 413 with
"Wiki quota exceeded (50MB limit)" - Web UI: 403 on save (WRITE stripped). Generic permission denied — quota-specific message is a follow-up.
- Dashboard: Reads
disk_usage_bytesfromrobot.dbvia management API (15-min lag from cron).
Files to Modify
| Repo | File | Change |
|---|---|---|
| robot.wtf | app/resolver.py |
_get_wiki_stats(), quota check after swap, stats table in init, storage patch |
| robot.wtf | ansible/roles/quota/templates/wiki-quota.sh.j2 |
Write to wiki.db + robot.db |
| robot.wtf | ansible/roles/deploy/tasks/main.yml |
pip install otterwiki-wikistats |
| new repo | otterwiki-wikistats |
Plugin: setup, page_saved, page_deleted hooks |
Test Plan
- Quota read from wiki.db — over limit → WRITE stripped
- Under limit → pass-through
- API over-quota → 413
- Fallback to robot.db when stats table missing
- Plugin: page count updated on save/delete
- Plugin: uses
_state["storage"]not stale reference
Open Questions
- Quota check must move to after
_swap_database()— verify no regression on API 413 path - Cron user permissions on wiki.db files
- Plugin
_statedict convention — follow existing pattern fromotterwiki-api
