zwesty
Write-ups / Day 12 / Warmups
Day 12 · Mon, Oct 12 · Warmups

Back at You

Prey slaughtered

String reversal as a decoding layer, per-line multi-encoding decoding, bounding a search under a deadline, choosing between ambiguous decodes

STTMClaude Homebase Both

Flags are shortened to their first 8 and last 4 characters because they're unique per team.

Challenge ID
warmups-day-12 (+ /time_trial, /mastery)
Solved
2026-10-12: Single Solve and Time Trial CORRECT on the first submit (by 09:07:57 ET). Mastery expired at 09:09 (the solver ran past the 30 s clock on a one-attempt route); CORRECT at 16:27:18 ET in untimed practice after Huntress's practice fix, so unranked
Player
Zwesty (solo), with Claude Code (Opus 5.5)

The challenge

"Maybe we started at the wrong end."

answer_id Question Format
message "Decode the assigned blob completely. What exact answer slug does its final non-empty decoded line instruct you to submit?" pattern: "three lowercase words separated by hyphens, followed by a hyphen and a two-digit number; submit the slug only"; trimmed

Reading the prompt: what it said we'd need

Clue What it pointed to What I did about it
"started at the wrong end" The text is written back to front Added reversal as a move. Like ROT13, it always "succeeds", so it can't be a normal decoder that's tried until something decodes
"Decode the assigned blob completely" Reversal stacks with the earlier days' layers Tried reversal on the whole blob, inside the layer search, and on each line of a Mastery blob
"final non-empty decoded line … slug" The answer sits at the end of a fixed sentence Used the fixed sentence as a check, once it became clear the Mastery needed one

What was in the files

  • Single Solve: blob.txt, 109 bytes: the instruction written back to front, nothing else (56-ztrauq-tesnus-ytsez :retsaM emaG eht …). Slug zesty-sunset-quartz-65.
  • Time Trial: blob.txt, 108 bytes: the same template, reversed. Slug jaunty-banner-dune-97.
  • Mastery: one zip of 58 blobs (blob-01.txt … blob-58.txt). Every blob has 12 labelled lines (NN<TAB>…), each holding about 9 characters of the sentence, each line in its own encoding, in a fixed pattern: Base64 (twice), ROT13, hex, 8-bit binary, decimal, octal, percent, HTML entities, \u escapes, Base32, and one reversed line, always the last (for example 89-enud-t for …t-dune-98). This is Day 11's Mastery template with reversal added.

Single Solve

Our automated morning solver (a scheduled script on our Kali VM) stopped cleanly, as designed: the Day 10 Warmups solver found "no instruction line after layers ['rot13']" (its own ROT13 guess, which led nowhere) and sent nothing. Then the morning run hit HTTP 429 at 09:00:20.

Our new solver wraps Day 10's Thirty-Two Below (and through it Days 1–9). Reversal only runs when the old chain finds no instruction, so earlier days' answers can't change. It tries three things: the whole blob reversed then the old chain; a search over {Day 1's decoders, ROT13, reverse} that never repeats ROT13 or reverse back to back; and Day 2's per-line decoder with reversal added to each line's moves.

A test caught a worse problem than a crash (09:05). On a made-up per-line blob with a reversed line, the old chain didn't stop: it returned a wrong slug, erjfanir-yhane-bggre-42. Day 2's check only asked that the last line contain "submit"/"answer" and one slug-shaped word. A stricter check was added: the slug must end the line, and the words before it must be common English. Today's Single Solve wasn't affected (the old chain stopped cleanly on it).

Replay of every saved Warmups attempt: 41 sets, Days 1–11 identical, Day 12 newly solved. Then the answer was sent: CORRECT (ada2ddfd…f625).

Time Trial

CORRECT on the first attempt. The plain start was timed (30 s) and replied unique_attempts_remaining: 0.

started_at  2026-10-12T13:07:55.695Z
deadline    2026-10-12T13:08:25.695Z   (30 s)
answers     1   jaunty-banner-dune-97
start       426 ms
artifact    308 ms
solve         1 ms
submit      948 ms
TOTAL      1.68 s
result      CORRECT   flag 6caa7aea…9690

Mastery: expired, then CORRECT in practice

Started at 13:08:33 with a 30 s clock and 58 blobs. The solver never finished, so nothing was submitted.

What went wrong: each real blob has 12 lines, and the old chain can't undo the reversed one, so for every blob: 1. Day 2's per-line decoder tried every combination of its top decodes per line (up to 4¹² ≈ 16.7 million) before giving up. That's 4–5 s per blob. 2. Then the new whole-blob search fanned out on a 12-line blob with no limit.

So 58 blobs needed minutes, not seconds. The tests and the Single Solve only had 1–4-line blobs, so nothing showed the cost. The process was killed at 09:10.

Why it can't be retried: the start had said unique_attempts_remaining: 0 (the Time Trial had too). At 13:20:47 the solver sent retry: 409 retry_variants_unavailable. The solver didn't treat that as a stop and carried on to start and submit; both replied expired, so no answers were judged. At 13:21:54 one direct practice (the status said next_op: practice): the same 409. That is the D-Day situation from Day 11: only Huntress can reopen it. We decided not to open a ticket, as Discord had been discussing it for days.

The fix (offline, on the expired attempt's own blobs): - Bounded: Day 2's per-line pass copied with a 20,000-combination budget (same answers whenever it finds one), and the whole-blob search capped at 3,000 states. - Template walk: go through the lines in label order, keeping only decodes that continue "Nice work decoding this warmup! To solve, submit this exact answer to the Game Master: " exactly, then only slug characters. That pins every sentence line, however its decodes rank. - Choosing a slug: a reversed or ROT13'd slug tail is slug-shaped too (g-qhar-98 vs t-dune-98). Rank by words seen in earlier accepted slugs (a list of 142 words), then dictionary words, then words with a vowel. An even tie stops rather than guessing. For labelled blobs the walk always runs; if it disagrees with the old chain, the better-ranked slug wins.

All 58 blobs then decoded to clean slugs in about 5 s (budget 7.5 s).

A rehearsal found four more problems before any of this went near a clock (every saved set, plus a generated 60-blob Mastery with reversal in it): - the walk stopped after 64 results, and junk slug tails filled them first; - onyx and balk are ROT13 of each other and both English (hence the vocabulary); - in 9 of 1,200 generated blobs the old chain built a junk tail (eag-nevar-recopper-80) that passed every check; - the generator's own random cuts made 2–3-character pieces no decoder can resolve (real blobs use ~9).

After the fixes: 1,200 generated blobs, 0 wrong, 0 stops, and every saved set unchanged.

Completed in practice (16:27 ET). At 15:54 John Hammond posted a list of the platform's problems. Item 2: sets weren't unique per team yet, and staff testing drained the shared pool, which is why every timed start said one attempt. Item 5: the fix for rejected practice continuations "should" be live. The status still said next_op: practice, so one practice was sent. It opened an untimed attempt (practice: true, no deadline) on the same artifact (sha e287ad6e…), and the hardened solver's 58 answers went in on one submit: CORRECT (f4a7ee7c…2894). Practice solves aren't ranked, so there's no speed time for this mode.

Time to solve

The morning solver started the Single Solve at 13:00:12 UTC and stopped cleanly on the new layer; the new solver's answer went CORRECT at 13:07:09, and the Time Trial followed in 1.68 s on its first attempt. The Mastery expired on its one attempt and was completed unranked, in untimed practice, at 16:27:18 ET (20:27 UTC), 7 h 27 min after the first start.

Takeaways

  • Correct isn't enough on a single-attempt clock; it has to be fast on Mastery-shaped input. From Day 13, no timed start of a new solver until it passes a rehearsal: every saved set inside a quarter of its clock, plus a generated Mastery with the new layer.
  • Every search needs a budget. The old per-line search was fine on every blob it could decode and a disaster on the first it couldn't.
  • Wrong is worse than stopped. A loose "this looks like the instruction" check let junk slugs through. A strong model of the answer (the fixed sentence, the known word list) beats a loose one, and ties should stop.
  • Our solver now protects the clock: the solve gets the time left minus 3 s; solvers that can work set by set submit what they have when time runs out; a refused retry or an expired start stops before any submit.