feat(protocol2): house registry board (Part B ph.3)

Overlay BridgeHousing (new): a diff sweep over BaseHouse.AllHouses ->
house.update / house.remove (owner, region, location, decay level, co-owners,
friends, placement price), complementing the existing house.decay transition
feed. HousingSweepSeconds (300s); wired into [bridge reload|sweepnow|status.
Stock ServUO has no "for sale" flag, so this is an owner->houses registry;
price is the placement value, not a listing.

Sidecar: houses board table with upsert/delete/all; main routes house.update/
remove into it; GET /houses served from the store.

Docs: INTEGRATION.md house.* events + /houses endpoint; PROTOCOL_2 ph.3 built.

Verified: sidecar cargo check clean; overlay compiles in the full ServUO
Scripts tree (0 errors, 0 warnings). Live run pending.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-17 08:05:47 -05:00
parent d47170581d
commit b858d526b8
7 changed files with 274 additions and 1 deletions

View File

@@ -78,6 +78,7 @@ pub async fn serve(addr: &str, state: AppState) -> anyhow::Result<()> {
.route("/guilds", get(guilds))
.route("/governors", get(governors))
.route("/online", get(online))
.route("/houses", get(houses))
.route_layer(middleware::from_fn_with_state(state.clone(), gate));
let app = Router::new()
@@ -730,6 +731,18 @@ async fn governors(State(st): State<AppState>) -> impl IntoResponse {
}
}
/// The house registry: every house's latest snapshot (owner/region/location/decay/value). Served
/// from the local board table, so it hydrates without the shard and survives an outage.
async fn houses(State(st): State<AppState>) -> impl IntoResponse {
match st.store.houses_all().await {
Ok(houses) => (StatusCode::OK, Json(json!({"houses": houses}))),
Err(e) => (
StatusCode::INTERNAL_SERVER_ERROR,
Json(json!({"error": e.to_string()})),
),
}
}
/// The current online population: total plus per-facet and per-region counts. This is the most
/// recent `presence.online` snapshot from the event store (so it survives a sidecar restart); the
/// live `presence.online` stream keeps it current, and `GET /history?kind=presence.online` gives the