From 1ab0cab80ae31c5494a4f4f10e7fcd7683699b8b Mon Sep 17 00:00:00 2001 From: wtclaude Date: Thu, 15 Oct 2026 06:45:27 -0500 Subject: [PATCH] =?UTF-8?q?feat(sidecar):=20protocol=2014=20=E2=80=94=20th?= =?UTF-8?q?e=20Dangerous=20Treasures=20start=20forward=20(PLAN=5FREDESIGNS?= =?UTF-8?q?=20=C2=A714.3.4)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit POST /dt/start, stamped dt.start whatever its body names, forwarded to the plugin and answered with its dt.opened or dt.error. The plugin remembers the key; DT despawns its own chest; nothing is kept here. dt.started, dt.won and dt.ended ride the feed like any other event (docs rust-link/PROTOCOL.md §20.8). 72 tests (one new), fmt and clippy clean. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01E14m6SuuY6i1vASFeGDBeY --- sidecar/src/main.rs | 5 +++++ sidecar/src/web.rs | 24 ++++++++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/sidecar/src/main.rs b/sidecar/src/main.rs index b2850a2..df08f77 100644 --- a/sidecar/src/main.rs +++ b/sidecar/src/main.rs @@ -198,6 +198,11 @@ use tracing_subscriber::EnvFilter; /// frames (24 of them, told apart by `event`) ride the feed like any other event, and hello's /// `console` like any other field. /// +/// Dangerous Treasures (§20.8, the module's PLAN_REDESIGNS.md §14.3.4) adds one forward, +/// `POST /dt/start`: open one treasure event for a run's step. The plugin remembers the key so a +/// retry never opens a second; DT despawns its own chest. `dt.started`, `dt.won` and `dt.ended` +/// ride the feed like any other event. +/// /// `docs/rust-link/PROTOCOL.md` is the specification — §8 the read path, §9 identity, §10 the /// mirror, §11 configuration, §12 clans, §13 the raid frame, §14 the leases, §15 the world verbs, /// §16 the rewards, §17 the map, §18 the optional mods, §19 the walk's fixes, §20 the step editor; diff --git a/sidecar/src/web.rs b/sidecar/src/web.rs index 299d690..a2447c7 100644 --- a/sidecar/src/web.rs +++ b/sidecar/src/web.rs @@ -125,6 +125,9 @@ pub async fn serve(addr: &str, state: AppState) -> anyhow::Result<()> { .route("/world/revert", post(world_revert)) // Protocol 14 (§20.5): one of the game's own world events, now. Kept, never reverted. .route("/world/call", post(world_call)) + // Protocol 14 (§20.8): open one Dangerous Treasures event. The plugin remembers the key; + // DT picks the spot and despawns its own chest, so nothing here is kept either. + .route("/dt/start", post(dt_start)) // Protocol 10 (§29): who took part, what they may redeem, and a line in chat. The tally // is counted and held by the plugin, the kit catalogue is Kits' own, and whether a chat // line was already said is the plugin's memory. These move lines, like everything above. @@ -563,6 +566,13 @@ async fn world_call(State(st): State, Json(body): Json) -> Resp forward_object(&st, body, "world.call", "a world event call").await } +/// Open one Dangerous Treasures event for a run's step (protocol 14). `dt.opened` (where it +/// opened, and `repeat` for a key already seen) or `dt.error` with a reason, `dt-not-ready` among +/// them. DT despawns its own chest, so nothing is remembered here. +async fn dt_start(State(st): State, Json(body): Json) -> Response { + forward_object(&st, body, "dt.start", "a Dangerous Treasures start").await +} + /// Start counting who takes part in a run. `tally.ok` or `tally.error` with a reason. async fn tally_open(State(st): State, Json(body): Json) -> Response { forward_object(&st, body, "tally.open", "a tally").await @@ -1295,6 +1305,20 @@ mod tests { assert!(stamp(json!("airdrop"), "world.call", "r-51").is_none()); } + /// Protocol 14, Dangerous Treasures: a start is stamped `dt.start` whatever its body names, so + /// the route can open a treasure event and nothing else, and its key and level pass through. + #[test] + fn protocol_14_dt_start_is_stamped() { + let body = json!({ "cmd": "world.call", "reqId": "theirs", "key": "12:3", "level": 2 }); + let stamped = stamp(body, "dt.start", "r-60").expect("an object is stamped"); + + assert_eq!(stamped["cmd"], "dt.start"); + assert_eq!(stamped["reqId"], "r-60"); + assert_eq!(stamped["key"], "12:3"); + assert_eq!(stamped["level"], 2); + assert!(stamp(json!(2), "dt.start", "r-61").is_none()); + } + /// Protocol 12: a title set is forwarded whole. The markup inside each `text` is the module's /// and the plugin's business, so it must arrive byte for byte as the website composed it. #[test] -- 2.49.1