| name | wabidb-engine-integration |
| description | Integrate WabiDB engine into wabi-server and close the assault queue gaps. |
| version | 0.1.0 |
| author | Hermes |
| platforms | ["linux"] |
| metadata | {"hermes":{"tags":["WabiDB","Integration","Projections","Persistence"]}} |
WabiDB Engine Integration
This skill captures the current state of the WabiDB engine integration into wabi-server and the assault queue gaps (projection-less handlers, persistence policy, event log replay). It provides the exact steps to close those gaps and complete the integration.
When to Use
- You need to integrate WabiDB into wabi-server
- You want to close the assault queue gaps (projection-less handlers, persistence policy, event log replay)
- You need to understand the current state of the WabiDB engine
- You want to reuse the integration patterns and gaps
Prerequisites
- Rust toolchain (stable + nightly for MIRI)
- WabiDB source at
/var/home/Ronin/wabi/core/crates/wabidb/
- wabi-server source at
/var/home/Ronin/wabi/core/crates/wabi-server/
- 656 wabidb tests passing, 44 wabi-server tests passing
WABIDB_ROOT_KEY env var set for engine bootstrap
How to Run
Invoke through the terminal tool from the Wabi monorepo root:
cd /var/home/Ronin/wabi
cargo test -p wabidb --lib
cargo test -p wabi-server
Quick Reference
- Adapter:
core/crates/wabi-server/src/adapter/mod.rs (1416 lines, 40 methods)
- Engine:
core/crates/wabidb/src/engine/mod.rs (654 lines, 14 projections)
- Projections:
core/crates/wabidb/src/projections/ (14 handlers)
- Domain:
core/crates/wabidb/src/domain/mod.rs (567 lines)
- Sequencer:
core/crates/wabidb/src/sequencer/mod.rs (800+ lines, 8 tests)
Procedure
1. Close the Assault Queue Gaps
Gap 1: Projection-less Handlers (7 items)
The adapter has methods that write events but have no projection handler:
ban_user / unban_user → bans index, no handler
mute_user / unmute_user → mutes index, no handler
deafen_user / undeafen_user → deafens index, no handler
touch_user → users index, should update last_seen_micros
upsert_channel_retention → channel_retention index, no handler
upsert_member_role → member_roles index, no handler
remove_channel_member → no handler (never cleans up channel_members index)
Fix: Add projection handlers in core/crates/wabidb/src/projections/:
write_file(path="core/crates/wabidb/src/projections/bans.rs", content="...")
write_file(path="core/crates/wabidb/src/projections/mutes.rs", content="...")
write_file(path="core/crates/wabidb/src/projections/deafens.rs", content="...")
write_file(path="core/crates/wabidb/src/projections/member_roles.rs", content="...")
write_file(path="core/crates/wabidb/src/projections/channel_retention.rs", content="...")
Register them in engine/mod.rs build_dispatch_table():
use crate::projections::bans::BansProjection;
use crate::projections::mutes::MutesProjection;
use crate::projections::deafens::DeafensProjection;
use crate::projections::member_roles::MemberRolesProjection;
use crate::projections::channel_retention::ChannelRetentionProjection;
let handlers: Vec<Arc<dyn Projection>> = vec![
Arc::new(BansProjection),
Arc::new(MutesProjection),
Arc::new(DeafensProjection),
Arc::new(MemberRolesProjection),
Arc::new(ChannelRetentionProjection),
];
Gap 2: Persistence Policy System (3 phases)
Phase 1: Add persistence policy projection
- Read per-stream policy, default to
Session
- Store policy in a new
persistence_policies index
Phase 2: Write filter in sequencer
- Skip disk write for
Off-policy streams
- Add
policy: PersistencePolicy to CommandCommit
Phase 3: Event log replay on startup
- Wire replay into
engine::open()
- Rebuild projections from segments
Fix:
- Add policy enum:
pub enum PersistencePolicy {
Session,
Off,
}
- Add policy to commit:
pub struct CommandCommit {
pub policy: PersistencePolicy,
}
- Filter in sequencer:
if commit.policy == PersistencePolicy::Off {
}
- Wire replay into
open():
pub async fn open(config: WabiDbConfig) -> Result<Self> {
self._replay_segments().await?;
}
Gap 3: Event Log Replay on Startup
Current: open() initializes empty ProjectionState → all data disappears on restart.
Fix: Add replay logic:
pub async fn replay_segments(&self) -> Result<()> {
}
Call it from open():
impl WabiDbEngine {
pub async fn open(config: WabiDbConfig) -> Result<Self> {
let mut engine = Self { ... };
engine.replay_segments().await?;
Ok(engine)
}
}
2. Verify the Integration
Run the full test suite:
cd /var/home/Ronin/wabi
cargo test -p wabidb --lib
cargo test -p wabi-server
cargo check -p wabi-server
3. Update the Kanban
Mark the assault queue cards as done:
hermes kanban complete wabidb-projection-less-handlers
hermes kanban complete wabidb-persistence-policy
hermes kanban complete wabidb-event-log-replay
Pitfalls
- Projection key encoding: Use composite keys (e.g.,
(channel_id, message_id)) to avoid collisions.
- Binary format alignment: Ensure handlers use the same encoding (bincode vs JSON) as the adapter writes.
- MIRI limitations: Filesystem isolation blocks
mkdir/open — use MIRIFLAGS="-Zmiri-disable-isolation" for full test runs.
- Secret redaction: Tool pipeline may corrupt env var references — rename
*_SECRET to *_KEY or *_PWD.
Verification
cd /var/home/Ronin/wabi
cargo test -p wabidb --lib 2>&1 | tail -3
cargo test -p wabi-server 2>&1 | tail -3
The skill is ready when all assault queue gaps are closed and the test suite passes.