Files
wizwar6e/deploy/feedback-reply.sh
T
Eric WagonerandClaude Fable 5.1 11e9f950c6 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
2026-09-21 12:08:55 -04:00

37 lines
2.4 KiB
Bash
Executable File

#!/bin/bash
# Answer a player's feedback report; the reply appears under it in their
# lobby ledger. Legacy reports without an id answer to their timestamp.
# deploy/feedback-reply.sh <host> <reportId> <resolved|by-design|open> <text...>
set -euo pipefail
HOST="${1:?usage: feedback-reply.sh <host> <reportId> <status> <text...>}"
REPORT_ID="${2:?usage: feedback-reply.sh <host> <reportId> <status> <text...>}"
STATUS="${3:?usage: feedback-reply.sh <host> <reportId> <status> <text...>}"
shift 3
TEXT="$*"
case "$STATUS" in resolved|by-design|open) ;; *) echo "status must be resolved, by-design, or open" >&2; exit 1;; esac
LINE=$(REPORT_ID="$REPORT_ID" STATUS="$STATUS" TEXT="$TEXT" node -e '
console.log(JSON.stringify({
reportId: process.env.REPORT_ID,
at: new Date().toISOString(),
status: process.env.STATUS,
text: process.env.TEXT,
}));')
printf '%s\n' "$LINE" | ssh "root@$HOST" 'cat >> /var/lib/wizwar/feedback.jsonl && tail -1 /var/lib/wizwar/feedback.jsonl'
# The desk's bell rings for the reply too, so Eric sees the exchange move:
# an event straight to Sentry from the droplet, with the DSN the service holds.
ssh "root@$HOST" "REPORT_ID='$REPORT_ID' STATUS='$STATUS' TEXT=\"\$(cat)\" python3 - <<'PY'
import json, os, re, uuid, urllib.request, datetime
svc = open('/etc/systemd/system/wizwar.service').read()
m = re.search(r'SENTRY_DSN=https://([0-9a-f]+)@([^/]+)/(\\d+)', svc)
if not m: raise SystemExit(0)
key, host, project = m.groups()
text = os.environ['TEXT']; rid = os.environ['REPORT_ID']; status = os.environ['STATUS']
event = {'event_id': uuid.uuid4().hex, 'timestamp': datetime.datetime.now(datetime.UTC).isoformat(), 'level': 'error', 'platform': 'other',
'message': {'formatted': f'Desk replies on report {rid} ({status}): {text[:100]}'}, 'fingerprint': ['report-reply', rid, datetime.datetime.now(datetime.UTC).isoformat()],
'tags': {'report': rid, 'status': status}, 'extra': {'text': text}}
body = json.dumps({'event_id': event['event_id'], 'sent_at': event['timestamp']}) + '\\n' + json.dumps({'type': 'event'}) + '\\n' + json.dumps(event)
req = urllib.request.Request(f'https://{host}/api/{project}/envelope/', data=body.encode(), headers={'Content-Type': 'application/x-sentry-envelope', 'X-Sentry-Auth': f'Sentry sentry_version=7, sentry_client=wizwar-desk/1, sentry_key={key}'})
try: urllib.request.urlopen(req, timeout=10); print('bell rung')
except Exception as e: print('bell failed:', e)
PY" <<< "$TEXT"