atagen

jelq

public

an http based roguelike rpg about jelqing

Star0
Watch0

Commit f39b10e20a0b

tarball

atagen <boss@atagen.co>2026-10-10 15:15 UTC

4 files changed+29-9
http: send X-Length instead of the self-report once the ruler is found

A measured player kept seeing the inflated X-Self-Reported-Length beside a true Content-Length on /length, so the ruler changed nothing in the stats they read every turn.
Modified file: src/headers.rs+1 additions
@@ -9,6 +9,7 @@ pub const X_FLOOR: HeaderName = HeaderName::from_static("x-floor");
99 pub const X_FORESKIN: HeaderName = HeaderName::from_static("x-foreskin");
1010 pub const X_FORUM_NOTE: HeaderName = HeaderName::from_static("x-forum-note");
1111 pub const X_GIRTH: HeaderName = HeaderName::from_static("x-girth");
12+pub const X_LENGTH: HeaderName = HeaderName::from_static("x-length");
1213 pub const X_OBSERVED_BY: HeaderName = HeaderName::from_static("x-observed-by");
1314 pub const X_POWERED_BY: HeaderName = HeaderName::from_static("x-powered-by");
1415 pub const X_SEED: HeaderName = HeaderName::from_static("x-seed");
Modified file: src/http/run.rs+10 additions−6 deletions
@@ -13,8 +13,8 @@ use super::{AppState, ctx::Ctx, meta, middleware::Compress, resource::Resource,
1313 use crate::{
1414 game::{Elder, FORUM_THREAD, Floor, Run, balance::SUSPICION_LIMIT},
1515 headers::{
16- X_CASH, X_EQ, X_FLOOR, X_FORESKIN, X_GIRTH, X_OBSERVED_BY, X_SELF_REPORTED_LENGTH, X_SHAME,
17- X_STAMINA, X_SUSPICION,
16+ X_CASH, X_EQ, X_FLOOR, X_FORESKIN, X_GIRTH, X_LENGTH, X_OBSERVED_BY,
17+ X_SELF_REPORTED_LENGTH, X_SHAME, X_STAMINA, X_SUSPICION,
1818 },
1919 locale::Locale,
2020 problem::{PROBLEM_BASE, Problem},
@@ -171,10 +171,14 @@ pub fn finish(run: &mut Run, ctx: &Ctx, secret: &Secret, mut response: Response)
171171 }
172172 let shame = settle_shame(run, ctx, secret);
173173 let mut stats: Vec<(HeaderName, String)> = vec![
174- (
175- X_SELF_REPORTED_LENGTH,
176- format!("{:.2}", run.self_reported()),
177- ),
174+ if run.items.ruler {
175+ (X_LENGTH, format!("{:.2}", run.length))
176+ } else {
177+ (
178+ X_SELF_REPORTED_LENGTH,
179+ format!("{:.2}", run.self_reported()),
180+ )
181+ },
178182 (X_GIRTH, format!("{:.2}", run.girth)),
179183 (
180184 X_FORESKIN,
Modified file: src/tests.rs+13 additions
@@ -824,3 +824,16 @@ async fn caged_drawers_are_noisy_and_eventually_give_up_the_key() {
824824 .all(|s| *s == StatusCode::NO_CONTENT)
825825 );
826826 }
827+
828+#[tokio::test]
829+async fn the_ruler_replaces_the_self_report() {
830+ let app = seeded_with(Floor::Bedroom, |_| {});
831+ let before = send(&app, "GET", "/runs/cafebabe", &[], "").await;
832+ assert!(before.headers().contains_key("x-self-reported-length"));
833+ assert!(!before.headers().contains_key("x-length"));
834+
835+ let app = seeded_with(Floor::Bedroom, |run| run.items.ruler = true);
836+ let after = send(&app, "GET", "/runs/cafebabe", &[], "").await;
837+ assert!(!after.headers().contains_key("x-self-reported-length"));
838+ assert!(after.headers().contains_key("x-length"));
839+}
Modified file: src/ui.html+5 additions−3 deletions
@@ -63,7 +63,8 @@ const STATS = [
6363 ["x-shame", "Shame"],
6464 ["x-cash", "Cash"],
6565 ];
66-const QUIET = new Set(["link", "set-cookie", "server", "x-powered-by", "cache-control", "content-length", "content-type", "date"].concat(STATS.map(s => s[0])));
66+const MEASURED = ["x-length", "Length"];
67+const QUIET = new Set(["link", "set-cookie", "server", "x-powered-by", "cache-control", "content-length", "content-type", "date"].concat(STATS.map(s => s[0]), MEASURED[0]));
6768
6869 const FIELDS = {
6970 seed: { label: "seed (unranked)", kind: "text" },
@@ -198,9 +199,10 @@ function chooseTarget(t) {
198199 function renderStats(headers) {
199200 const table = $("stats");
200201 table.replaceChildren();
201- for (let i = 0; i < STATS.length; i += 2) {
202+ const stats = STATS.map(s => s[0] === "x-self-reported-length" && headers && MEASURED[0] in headers ? MEASURED : s);
203+ for (let i = 0; i < stats.length; i += 2) {
202204 const row = el("tr");
203- for (const [name, label] of STATS.slice(i, i + 2)) {
205+ for (const [name, label] of stats.slice(i, i + 2)) {
204206 const value = headers ? headers[name] : undefined;
205207 row.append(el("th", { align: "left", textContent: label }), el("td", { textContent: value === undefined ? "—" : value }));
206208 }