# Bitch Bot — First-Boot Server Provisioner

**Named by:** Holly (The Catalyst)
**Architecture:** Locked via 4-round Gemini consultation — see `firefrost-operations-manual/docs/consultations/gemini-modpack-installer-followup-2026-04-15.md`
**REQ:** `docs/code-bridge/archive/REQ-2026-04-15-bitch-bot.md`
**Status:** Source scaffold complete on Nitro. Compile on Dev Panel.

## Project Structure
- `1.21.1/` — NeoForge (Java 21, Gradle 8.8, moddev 2.0.141) — primary target
- (1.20.1/Forge port can be added later if needed)

## What Bitch Bot Does

On `ServerStartedEvent`, if `provision.json` exists in the server root:

1. Reads original spawn coords from `level.dat` via `level.getSharedSpawnPos()`
2. Downloads the schematic from `schematic_url`, verifies SHA-256 against `schematic_hash`
3. Pastes Sponge Schematic v2 (`.schem`) at `spawn_coords` (centered if `paste_origin == "center"`)
4. Places impulse command blocks at every position in `command_blocks[]` with `/tp @p [orig_x] [orig_y] [orig_z]` baked into NBT
5. Places oak signs at every entry in `rules_signs[]` with up to 4 lines each
6. Sets worldspawn to `spawn_coords + worldspawn_offset`
7. Sets gamerule `doFireTick false`
8. Writes a YAWP region config to `world/serverconfig/yawp/regions/{name}.json`
9. If `self_destruct_on_success: true` AND every step succeeded: renames `BitchBot-1.0.0-neoforge-1.21.1.jar` → `.jar.disabled`
10. Renames `provision.json` → `provision.json.applied` so it doesn't re-trigger

## Failure Behavior
- Every step is independently try/catch'd. A failure logs and moves on.
- If ANY step fails, self-destruct does NOT fire — admin can fix the issue and reboot for retry.
- The server is NEVER crashed by Bitch Bot. The outermost handler in `BitchBot.onServerStarted` is a `Throwable` net.

## Source Files

```
src/main/java/com/firefrostgaming/bitchbot/
├── BitchBot.java              # @Mod entry, ServerStartedEvent listener
├── Provisioner.java           # Sequenced step runner + success tracking
├── ProvisionConfig.java       # Gson POJO for provision.json
├── SchematicLoader.java       # HTTP download + SHA-256 + Sponge v2 NBT parser + paste
├── CommandBlockPlacer.java    # Impulse command blocks with TP NBT
├── SignPlacer.java            # Oak signs with 4 lines of front text
├── YawpConfigWriter.java      # Drops YAWP region JSON to world/serverconfig/yawp/regions/
└── SelfDestruct.java          # Locates own jar via ProtectionDomain, renames to .jar.disabled
```

## Building (Dev Panel only — no Java/Gradle on Nitro)

```bash
cd /opt/mod-builds/firefrost-services/services/bitch-bot/1.21.1
source use-java 21
/opt/gradle-8.8/bin/gradle build --no-daemon
# Output: build/libs/BitchBot-1.0.0-neoforge-1.21.1.jar
```

## Provisioning a New Server

1. Drop the jar into the server's `mods/` folder
2. Drop a populated `provision.json` (see `sample-provision.json`) into the server root (next to `server.properties`)
3. Boot the server
4. Watch the log — Bitch Bot prints every step to `[BitchBot]` lines
5. Once provisioning is reported successful, the jar renames itself to `.jar.disabled` and provision.json renames to `.applied`

## Architectural Notes from Gemini

- **Do NOT** write to .mca region files from Node.js — corruption-prone on 1.20+. The whole reason Bitch Bot exists as a real mod and not Node-side region manipulation.
- **Do NOT** rely on RCON or WorldEdit console — everything is in-process via the Forge API.
- **YAWP config** is written as a dropped file in `world/serverconfig/yawp/regions/{name}.json`. If the on-disk format diverges from what YAWP expects, fix `YawpConfigWriter.java` — it's the only file that touches the format.
- **BlockEntities and Entities tags in the .schem are ignored.** Spawn buildings should be vanilla blocks only. (If we later need item frames or armor stands, extend `SchematicLoader.pasteAt`.)

## Risk Areas to Test on First Real Run

1. **Schematic parsing** — only tested against the Sponge v2 spec, not against real WorldEdit `.schem` output. If parsing fails, palette key strings or varint stream encoding may need tweaks.
2. **Command block NBT** — `cbe.getCommandBlock().setCommand(...)` should persist, but verify the command actually fires when a player presses the button on top.
3. **Self-destruct on Linux** — every Firefrost server is Linux, so `Files.move` should work in-place. Windows fallback uses `deleteOnExit`.
4. **YAWP file format** — `YawpConfigWriter` writes a reasonable JSON shape but the actual YAWP mod schema may need adjustment. Watch for "region not loaded" warnings on second boot.
