zwesty
Write-ups / Day 24 / Warmups
Day 24 · Sat, Oct 24 · Warmups

String Theory

Prey slaughtered

Netstrings (<length>:<data>,), strict length-prefixed parsing, layered blob lines, regression rehearsal

STTMClaude Homebase Both

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

Challenge ID
warmups-day-24 (+ /time_trial, /mastery)
Solved
2026-10-24: all three modes CORRECT on the first submit. The solver stopped on the Single Solve ("no instruction line found", nothing sent); Claude decoded it by hand (CORRECT 09:01:20 ET). A helper then built the reading, and the ranked Time Trial (09:08:00) and ranked Mastery (09:08:06) were CORRECT on their first runs. 7 min 22 s from the first start request on this lane (09:00:44 ET) to the Mastery CORRECT
Player
Zwesty (solo), with Claude Code (Opus 5.5): our automated morning solver (a scheduled script on our Kali VM) started the Single Solve and stopped; Claude solved the Single by hand; a Claude helper agent built the netstring reading, ran the checks, and ran both timed modes

The challenge

"Count carefully. The comma knows where to stop."

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

Mastery asked the same question once per blob (set1.message … set118.message).

Reading the prompt: what it said we'd need

Clue What it pointed to What I did about it
"Count carefully" A length you have to count: the decimal length prefix of a netstring Read the digits before : as the payload length and take exactly that many characters
"The comma knows where to stop" The netstring terminator: every frame ends in , The reader requires the , right after the counted payload, or rejects the frame
"String Theory" (title) Netstrings Confirmed the reading
"submit the slug only" (format) The answer is the slug alone Same as Day 23; no trailer showed up today

What was in the files

  • Single Solve: blob.txt, 444 bytes: 111 netstrings of one character each, 1:N,1:i,1:c,1:e,1: ,1:w,…. Joined, the payloads read "Nice work decoding this warmup! To solve, submit this exact answer to the Game Master: jaunty-compass-mosaic-76".
  • Time Trial: blob.txt, 428 bytes, the same template (107 one-character frames) with a different slug (brave-tent-laurel-70).
  • Mastery: one zip of 118 blobs (73,892 bytes). Each blob has 24 labelled lines, the history pattern of the earlier days: line 22 Base64 zlib (Day 22), line 23 Ascii85 (Day 23), and line 24 netstrings (today), for example 1:e,1:r,1:-,1:8,1:2, (er-82) on line 24 of blob-01.txt.

So the timed variants used the same template with different values; only the frame count changed with the sentence length.

Single Solve

The solver: stopped, nothing sent

started_at  2026-10-24T13:00:44.261Z   (solver)
deadline    none (Single Solve)
answers     none
result      STOP: no instruction line found (per-line, Day 10 decoders, whole-blob reverse, search; atbash; caesar
            search; new-layer search; trailer reading); not submitting. Timed modes not started.

This stop was correct. None of the solver's readings knew netstrings, and its 3-move "new-layer search" didn't find them, so any value sent would have been a guess.

By hand (Claude)

The pattern 1:N,1:i,… is readable by eye: each frame is one character. Claude joined the payloads, read the sentence above, and sent the one answer it gave: jaunty-compass-mosaic-76.

started_at  2026-10-24T13:00:44.261Z   (same attempt, submitted by Claude at 13:01:19)
answers     1   jaunty-compass-mosaic-76
result      CORRECT   flag 2ea1815c…0666   (13:01:20)

The solver update (helper)

The helper built a new Warmups solver on top of the Day 23 one: - One new reading, netstring_text, added to the solver's text decoders at cost 1, next to the older readings. It is not gated on "the older readings found nothing" (a lesson from Day 22), so it runs in the whole-blob search and on every Mastery piece, and the stacking added on Day 17 gives netstring-over-older and older-over-netstring at the same cost. - Strict grammar: <digits>:<data>, frames must cover the input exactly (outer whitespace aside), with any lengths; the payloads are joined. One malformed frame rejects the whole input. If the whole doesn't parse and there are two or more lines, every line must parse (offered joined by newlines and joined directly). - Our rehearsal tool gained a netstring layer, so synthetic blobs can use it.

Checks before the timed runs: - Tests: 21 OK, including the real Single blob, multi-character and random frame sizes, frames across lines, nested Base64/hex/ROT13/netstring, a 24-line Mastery with line 24 in 7 netstring shapes (stacked ones included), the Day 23 trailer, malformed input stopping cleanly, and a 60-set Mastery in 0.25 s. - A regression rehearsal against the previous day's puzzles plus 60 synthetic netstring blobs: 114 saved attempts, slowest 0.93 s, per-set identical; against the previous solver 113 identical, 1 newly solved (today's Single), 0 changed; synthetic 60 of 60. A second rehearsal with other historical layer shapes also passed.

Time Trial

CORRECT on the first attempt, ranked.

started_at  2026-10-24T13:07:59.303Z
deadline    2026-10-24T13:08:29.303Z   (30 s)
answers     1   brave-tent-laurel-70
start        115 ms after started_at
artifact     622 ms after started_at
solve        638 ms after started_at   (16 ms)
submit      1371 ms after started_at
TOTAL       ~2.14 s
result      CORRECT   flag 7af9fbb9…0e0c

Mastery

CORRECT on the first attempt, ranked (135 s clock).

started_at  2026-10-24T13:08:04.971Z
deadline    2026-10-24T13:10:19.971Z   (135 s)
answers     118
start         96 ms after started_at
artifact     426 ms after started_at
solve        775 ms after started_at   (349 ms)
submit      1510 ms after started_at
TOTAL       ~2.15 s
result      CORRECT   flag da75afc2…e522

No retries, no rejected values, no rate limit. Afterwards this solver became our default Warmups solver for the following days.

Time to solve

All three modes were solved by 09:08:06 ET, 8 min 6 s after release (7 min 22 s from the first start request on this lane). The Single Solve was decoded by hand at 09:01:20; the Time Trial and Mastery were both ranked and each went through on the first submit.

Takeaways

  • Solve the Single by hand, build the reader for the timed modes. A one-character-per-frame Single is readable by eye; that put the Single in at 09:01:20 while the reading was written.
  • Stopping was right. The solver's searches found nothing and it sent nothing, so both ranked runs were first attempts.
  • Add a new layer as an established reading, not a fallback. Cost 1, never gated: it then works whole-blob, per line, and stacked without extra code.
  • Parse framed formats strictly. Requiring the frames to cover the input exactly, with the comma in place, means a wrong reading rejects instead of producing near-text.
  • The gap was the build time, not the solve. About 6.5 minutes passed between the Single and the Time Trial; a pre-built netstring reading would have saved them.