The challenge
There are only two sides to this story.
The question, word for word Days 1–3:
Decode the assigned blob completely. What exact answer slug does its final non-empty decoded line instruct you to submit?
Answer format: word-word-word-NN, trimmed. Mastery: 18 blobs (Days 1–3 had 3, 8, and 13).
Reading the prompt: what it said we'd need
| Clue | What it pointed to | What I did about it |
|---|---|---|
| "Only two sides" | Base 2, binary: every digit is one of two values | Add a binary decoder |
| "Two of a Kind" (the title) | A pair: 0 and 1 | — |
| The question is identical to Days 1–3 | A compounding day: Base64, ROT13, and hex will be back in Mastery | Build on Day 3's solver |
| Mastery has gained a line each day (2, then 3) | Day 4's Mastery would have 4 lines, the last in binary | Already handled by the per-line decoder, or so I thought (see Mastery) |
| The next three days' prompts were already posted | Day 5: "reduced to numbers" (decimal). Day 6: "eight fingers" (octal). Day 7: "my address bar" (URL percent-encoding) | Add all four number decoders now, so Days 5–7 start ready |
What was in the files
Every blob decoded to the familiar sentence: "Nice work decoding this warmup! To solve, submit this exact answer to the Game Master: <slug>".
| Mode | Delivered as | Raw format |
|---|---|---|
| Single Solve | blob., 998 B |
The whole sentence as space-separated 8-bit groups |
| Time Trial | blob., 980 B |
The same |
| Mastery | 18 separate blob. files (not one zip, unlike Days 2–3) |
Four labelled lines per blob: 01 Base64, 02 ROT13, 03 hex, 04 binary |
The Single Solve blob, raw (start only) and decoded:
01001110 01101001 01100011 01100101 00100000 01110111 01101111 …
Nice work decoding this warmup! To solve, submit this exact answer to the Game Master: witty-starfish-turtle-96
How to read binary by eye: groups of 8 bits are one character each. 010 starts lowercase letters (0x60–0x7f), 0100 uppercase, and 00100000 is a space. 01001110 = 64+8+4+2 = 78 = "N".
A Mastery blob, split across four encodings, one per day so far (the hex line is shortened here):
01<TAB>TmljZSB3b3JrIGRlY29kaW5nIHRoaXMgd2Fy
02<TAB>zhc! Gb fbyir, fhozvg guvf
03<TAB>657861637420616e…
04<TAB>01110011 01110100 01100101 01110010 00111010 00100000 01111010 …
| Line | Encoding | Decodes to |
|---|---|---|
01 |
Base64 (Day 1) | "Nice work decoding this war" |
02 |
ROT13 (Day 2) | "mup! To solve, submit this " |
03 |
Hex (Day 3) | "exact answer to the Game Ma" |
04 |
Binary (Day 4) | "ster: zippy-basket-ripple-42" |
Single Solve: CORRECT
Started at 15:27:54 UTC. The blob's SHA-256 matched. One binary layer gave witty-starfish-turtle-96. CORRECT at 15:29:27, flag 018069c0…8971.
The solver
Our Day 4 solver loads Day 3's solver by path (Days 1–3: the Base64 family, ROT13, per-line decoding, loose hex) and adds four number decoders:
| Decoder | For | Accepts |
|---|---|---|
| binary | Day 4 | Spaced 8-bit groups, or one run of bits |
| decimal | Day 5 (expected) | 78 105 99, 78,105,99 |
| octal | Day 6 (expected) | 116 151 143, \116\151, 0o116 |
| percent | Day 7 (expected) | %4E%69, Nice%20work |
Order matters, and a test caught a trap:
- Binary before decimal, because 0/1 groups are also valid decimal numbers.
- Decimal before octal. An 8 or a 9 rules octal out, and octal read as decimal gives bytes above 127, which fail the printable check.
- All four before Day 1's line-label stripper. That stripper reads 78,105,99,… as "label 78, then a payload", and peeled one number per round until it hit the 64-layer safety limit. The comma-separated decimal test found it before anything was submitted.
8 tests at first (9 after Mastery): each format in its variants, octal not misread as decimal, mixing with Base64 and ROT13, a four-line per-line blob, and garbage refused.
Time Trial: 1.51 s of a 6-second clock
started_at 2026-10-07T15:29:28.817Z deadline 2026-10-07T15:29:34.817Z
artifact blob.txt 980 bytes sha256 ee99e57f491ac205… (checked)
message: jaunty-daisy-pebble-47
start 445 ms
artifact 379 ms
solve 0 ms
submit 688 ms
TOTAL 1513 ms
result CORRECT flag 4214e96f…7371
Mastery: CORRECT on the third attempt
| Attempt | What happened | Submitted? |
|---|---|---|
| 1 (15:29:32, 7 s clock) | The Game Master returned HTTP 503 temporarily_ mid-run. Our timed script stopped |
No |
| 2 (retry, 15:32:08) | 18 separate files, all hashes checked. The solver stopped on 16 of 18 blobs (see below) | No |
| 3 (retry, 15:34:22) | All 18 decoded. CORRECT | Yes |
Both failures stopped before submitting, so no wrong answer was ever sent. Attempt 1 also had a slip of mine: a second, hidden Mastery run chained into the same command. Its start got a 503 too and did nothing, but it shouldn't have been there.
Why attempt 2 failed: a line with no ordinary words
The per-line decoder (built on Day 2) picks each line's decoding by counting common English words: "the", "answer", "submit", and so on. Line 4 was ster: zippy-basket-ripple-42: the tail of "Master" plus three random slug words, none of them common. It scored 0, the same as the raw binary digits, and the tie rule ("fewer layers wins") kept the raw digits. With no instruction to be found, the solver refused to answer. Blobs 06 and 08 passed only because their lines split at different points.
The fix, in the shared per-line decoder: 1. A second score, "naturalness": the share of letters and spaces, halved when the chunk has no space or hyphen at all (Base64 and hex never do). Readable text now beats digit runs and encoded strings. 2. Combinations: keep each line's top 4 candidates, and try them together, best first, until the joined text reads as the instruction with exactly one slug. Even if one line's best guess is wrong, the right combination is found, in about 0.5 ms per blob.
Checked before the retry: all 18 failed blobs decoded, the 21 real Mastery blobs from Days 2 and 3 still gave their accepted answers, and all three days' tests passed, plus a new test built from the real failing blob.
started_at 2026-10-07T15:34:22.720Z deadline 2026-10-07T15:34:29.720Z
18 artifacts blob.txt, 374–386 bytes each (all checked)
set1.message: zippy-basket-ripple-42 … set18.message: proud-chimney-nugget-67
retry 1855 ms
start 379 ms
solve 9 ms
submit 719 ms
TOTAL 4050 ms
result CORRECT flag 89314f7a…480a
The retry call itself took 1.86 s, like every Mastery start today. With 18 downloads in parallel, the whole run still finished 3 seconds inside the clock.
Time to solve
All three modes were solved on 2026-10-07 by 15:34:27 UTC, 6 min 33 s after the first start. The Single Solve took 93 s and the Time Trial went through first time in 1.51 s; the Mastery passed on its third attempt in 4.05 s, after a server 503 and a solver stop, neither of which sent anything.
Takeaways
- Read ahead. The later days' prompts were already posted, so the Day 4 solver was built for Days 5–7 too.
- A scorer that counts words fails on text without words. Slugs, IDs, and fragments carry no common English. Use a second signal (letters and spaces versus digits and encoded strings) and test combinations rather than trusting each piece's best guess alone.
- Decoder order is a design decision. Binary is valid decimal, decimal can look like a labelled line, and octal can look like decimal. Each conflict needs a rule, and a test.
- Stopping is a feature. Both failed Mastery attempts stopped before submitting, one on a server error and one on its own doubt. Neither cost anything but a retry (254 of 255 attempts remained).
- Check what a command will actually run. A second Mastery run was chained in by mistake. It was harmless this time, but timed runs deserve one deliberate command each.