Reports are threads, and every turn of one rings the desk's bell
A player answers the desk under its reply from their lobby, proven by the seat the report was filed from; the lobby shows the exchange in order and says whose word is pending. A new report, a player's answer, and a desk reply each raise a Sentry issue on the keeper's phone — the first two from the server, the last from the reply script itself, straight to Sentry from the droplet. The Desktop digest lists the answers, and the desk's rule reads a report as reopened when the last word is the player's. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Jm2auWk6RP71CjaAb4FMoG
This commit is contained in:
co-authored by
Claude Fable 5.1
parent
ffbca5bfb9
commit
11e9f950c6
@@ -1064,9 +1064,48 @@ wss.on("connection", (socket, req) => {
|
||||
happened,
|
||||
expected: clean(msg.expected),
|
||||
});
|
||||
// The desk's bell: one issue per report, the gist in the title.
|
||||
if (process.env.SENTRY_DSN) {
|
||||
Sentry.captureMessage(`Report from ${session.playerId ?? "the gallery"} in ${room.id}: ${happened.slice(0, 100)}`, {
|
||||
level: "error",
|
||||
fingerprint: ["report", reportId],
|
||||
tags: { room: room.id, report: reportId, player: session.playerId ?? "(gallery)" },
|
||||
extra: { happened, expected: clean(msg.expected), link: `${PUBLIC_URL}/join/${room.id}`, seq: room.log.length },
|
||||
});
|
||||
}
|
||||
send(socket, { type: "feedbackReceived", id: reportId });
|
||||
break;
|
||||
}
|
||||
case "feedbackAnswer": {
|
||||
// A player's word under the desk's reply, from their lobby: the
|
||||
// seat is proven as the ledger proves it, and the report must be
|
||||
// theirs. Each answer rings the desk's bell.
|
||||
const seat = (msg.seat ?? {}) as Record<string, unknown>;
|
||||
const roomId = String(seat.roomId ?? "").toUpperCase();
|
||||
const name = String(seat.name ?? "");
|
||||
const proof = peekSummary(roomId, name, typeof seat.token === "string" ? seat.token : null);
|
||||
if (proof === null || proof === "badToken") return send(socket, { type: "error", message: "that seat is not yours to answer from" });
|
||||
const reportId = String(msg.reportId ?? "");
|
||||
const report = readFeedback().find((r) => r.id === reportId);
|
||||
if (!report || report.player !== name || report.roomId !== roomId) return send(socket, { type: "error", message: "no such report of yours" });
|
||||
const text = String(msg.text ?? "").replace(/[\u0000-\u0009\u000b-\u001f\u007f]/g, " ").trim().slice(0, 2000);
|
||||
if (!text) return send(socket, { type: "error", message: "say something" });
|
||||
if (!reportsPerAddress.allow(session.address)) {
|
||||
return send(socket, { type: "error", message: "the desk has plenty from you for now — more in an hour" });
|
||||
}
|
||||
const at = new Date().toISOString();
|
||||
appendFeedback({ reportId, from: "player", player: name, text, at });
|
||||
if (process.env.SENTRY_DSN) {
|
||||
Sentry.captureMessage(`${name} answers on report ${reportId} (${roomId}): ${text.slice(0, 100)}`, {
|
||||
level: "error",
|
||||
fingerprint: ["report-answer", reportId, at],
|
||||
tags: { room: roomId, report: reportId, player: name },
|
||||
extra: { text, link: `${PUBLIC_URL}/join/${roomId}` },
|
||||
});
|
||||
}
|
||||
send(socket, { type: "feedbackReceived" });
|
||||
break;
|
||||
}
|
||||
case "myFeedback": {
|
||||
// Reports for every seat this browser can prove — the same token
|
||||
// check as the games ledger, and just as wake-free.
|
||||
@@ -1080,8 +1119,7 @@ wss.on("connection", (socket, req) => {
|
||||
if (result !== null && result !== "badToken") proven.push({ roomId, name });
|
||||
}
|
||||
const reports = readFeedback()
|
||||
.filter((r) => proven.some((s) => s.roomId === r.roomId && s.name === r.player))
|
||||
.map(({ player: _player, ...r }) => r);
|
||||
.filter((r) => proven.some((s) => s.roomId === r.roomId && s.name === r.player));
|
||||
send(socket, { type: "feedbackList", reports });
|
||||
break;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user