Claude Opus 5.5 (effort default (no --effort flag) · thinking on) on AIS decoder: NMEA tag blocks, multipart reassembly and bit-level fields
AClaude Opus 5.5default · thinking on · Claude Code 2.1.299 (headless -p) · cloud · 2026-10-20 · by @bobsiopener
- Estimated cost
- $0.39
- Wall time
- 1.1h
- Human step-ins
- 0
- Outcome
- Partial
Compare with other models on this task →
Summary
Exact prompt
# AIS message decoder (NMEA 0183 AIVDM/AIVDO with tag blocks) `input.json` names `ais.log`, a synthetic receiver log. Write `solve.py` (Python 3 standard library only); `python solve.py input.json answer.json`. Fresh logs are generated. The full grammar is below; nothing else is needed. ## Line grammar - Lines are numbered from 0 (every physical line counts, including blank ones); blank lines are skipped. - Optional **tag block** prefix: `\<tag>*hh\` before the sentence. `hh` = XOR of all characters of `<tag>`, two hex digits. No closing `\`, or a wrong checksum -> error `bad_tag_block` (line dropped). `<tag>` is comma-separated `key:value`; `c:<integer>` is a UNIX time. - **Time**: each line that reaches the sentence stage sets the current time to its valid tag block's `c:` value, or to null if it has none. A decoded message's `time` is the current time at the line that completed it. - Sentence `!AIVDM,...` or `!AIVDO,...` (anything else -> `not_ais`). Checksum: XOR of characters between `!` and `*`, two hex digits, either case; wrong or missing -> `bad_checksum`. It must have exactly 7 comma fields: talker+type, fragment count, fragment number, sequential id (may be empty), channel, payload, fill bits; non-integer count/number/fill, or not 1 <= number <= count <= 9, or fill not in 0..5 -> `bad_fields`. - **Multipart** (count > 1), keyed by (sequential id, channel): fragment 1 starts a new message (if one was already open under that key, count `incomplete_multipart` and replace it). Fragment n > 1 must match an open message with the same count that has exactly n-1 parts; otherwise count `orphan_fragment` (and, if a message was open under that key, drop it and also count `incomplete_multipart`). Messages still open at the end of the file count `incomplete_multipart`. Only the last fragment's fill bits are used. - **Armoring**: each payload character c gives v = ord(c) - 48, minus 8 more if that is > 40; valid characters are `0`-`W` and `` ` ``-`w` only (else `bad_payload_char`). Concatenate 6-bit values (MSB first), then drop `fill` bits from the end. ## Messages (bit offsets, length; U = unsigned, I = two's-complement signed; MSB first) - All: type 0,6 U; MMSI 8,30 U. - Types 1, 2, 3 (need >= 168 bits, else `short_message`): status 38,4 U; rot_raw 42,8 I; SOG 50,10 U (0.1 kn; 1023 = null); lon 61,28 I and lat 89,27 I in 1/10000 minute (= /600000 degrees, round to 6 decimals; lon 181° and lat 91° = null); COG 116,12 U (0.1°, 3600 = null); heading 128,9 U (511 = null); second 137,6 U. - Type 18 (>= 168 bits): SOG 46,10; lon 57,28 I; lat 85,27 I; COG 112,12; heading 124,9; second 133,6 (same scaling and nulls). - Type 5 (>= 420 bits): IMO 40,30 U; callsign 70,42 (7 chars); name 112,120 (20 chars); ship_type 232,8; length = to_bow 240,9 + to_stern 249,9; beam = to_port 258,6 + to_starboard 264,6; draught 294,8 (/10, metres); destination 302,120 (20 chars). Text: 6-bit value indexes `@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_ !"#$%&'()*+,-./0123456789:;<=>?`; strip trailing `@` then trailing spaces. - Any other type -> `unsupported_type`. ## answer.json - `messages`: decoded messages in completion order. Each has `type`, `mmsi`, the fields above (keys `status`, `rot_raw`, `sog`, `lon`, `lat`, `cog`, `heading`, `second`; type 5: `imo`, `callsign`, `name`, `ship_type`, `length`, `beam`, `draught`, `destination`), plus `line` (the completing line), `time`, and `own` (true for `AIVDO`). - `errors`: {kind: count}, only kinds with a count above 0. - `vessels`: {mmsi as a string (sorted numerically): {"positions": number of type 1/2/3/18 messages, then from the latest such message with non-null lat and lon: "last_lat", "last_lon", "last_time"; "last_sog" from the latest position message with non-null SOG; type 5 fields (latest): "name", "callsign", "imo", "ship_type", "length", "beam", "draught", "destination"}} (keys present only if known). ## Scoring Hidden checks (partial credit; all must pass; floats within 1e-6): `checksums_and_framing` (bad_checksum, not_ais, bad_fields, bad_tag_block counts), `class_a_positions`, `class_b_positions`, `static_voyage_multipart`, `tag_block_times_and_own`, `all_error_counts`, `vessel_summary` on the given log; `fresh_run_1`, `fresh_run_2` (everything). 30-second limit per run.
Every rule is stated, but errors compound: a wrong armor offset or signedness breaks every position; mishandled fragment state shifts message order and counts. Original benchmark task written for usecaserank.com (not based on a specific public post). Headless, offline run on a reproducible fixture. Each run's notes say how its cost was measured (estimates are marked).
Success criteria: 1. checksums_and_framing 2. class_a_positions 3. class_b_positions 4. static_voyage_multipart 5. tag_block_times_and_own 6. all_error_counts 7. vessel_summary 8. fresh_run_1 9. fresh_run_2
Setup notes: Use Case Scout batch 12 case m04-ais-decoder (offline, synthetic fixture). Prepared with batch12/prepare.sh; hidden key/checker kept outside the agent's work dir (temp dir during the run). Prompt = TASK.md verbatim. Scored with the case's scorer: `python score.py WORKDIR KEYDIR` (python3, run from the case dir). Tools: Read/Write/Edit/Glob/Grep/Bash, web disabled. Single run, no retries. 1-min load average at scoring 0.43 (8 cores). Claude Code's own reported cost for claude-opus-5.5: $0.390287. Score: 5/9. Cost is an ESTIMATE: measured tokens x pricing.json list price (Claude Pro subscription, nothing billed); input_tokens include cache reads and writes. Single run.
Estimated cost List-price estimate; not actually billed.
Metrics
- Estimated cost
- $0.39
- Wall time
- 1.1h
- Human step-ins
- 0
- Turns
- 7
| Model | Input tok | Output tok | Cost |
|---|---|---|---|
| AClaude Opus 5.5anthropic/claude-opus-5.5effort default (no --effort flag) · thinking on | 170,649 | 5,606 | $0.39 |
Reproduce this run
- Use the use case prompt on the use case page.
- Same setup: Claude Opus 5.5 (anthropic/claude-opus-5.5, effort default (no --effort flag) · thinking on) via
Claude Code 2.1.299 (headless -p), cloud. - It counts as a success only if it meets every success criterion: 1. checksums_and_framing 2. class_a_positions 3. class_b_positions 4. static_voyage_multipart 5. tag_block_times_and_own 6. all_error_counts 7. vessel_summary 8. fresh_run_1 9. fresh_run_2
- Log model, tokens, wall time, human step-ins and the evidence log, then submit it as a reproduction. A different model? Submit a head-to-head rerun.
How runs are scored: Methodology.
Was this useful?
Automated checks
Trust 80% comes from these checks (how Trust % works).
- Run date is not in the future : passed
- Model is in the dated pricing table : passed
- Cost recomputed from tokens matches : passed
- Cached tokens are consistent : passed
- Output throughput is plausible : passed
- Autonomy matches step-ins : passed
- Step-ins do not exceed turns : passed
- Retries agree with first-try result : passed
- Evidence log SHA-256 matches : passed
- Evidence log is substantial : passed
Evidence log
[
{
"duration_api_ms": 179727,
"stop_reason": "end_turn",
"session_id": "[REDACTED]",
"total_cost_usd": 0.39028700000000005,
"usage": {
"input_tokens": 14,
"cache_creation_input_tokens": 31280,
"cache_read_input_tokens": 139355,
"output_tokens": 5606,
"output_tokens_details": {
"thinking_tokens": 941
},
"server_tool_use": {
"web_search_requests": 0,
"web_fetch_requests": 0
},
"service_tier": "standard",
"cache_creation": {
"ephemeral_1h_input_tokens": 31280,
"ephemeral_5m_input_tokens": 0
},
"inference_geo": "global",
"iterations": [
{
"input_tokens": 2,
"output_tokens": 560,
"cache_read_input_tokens": 12146,
"cache_creation_input_tokens": 15640,
"cache_creation": {
"ephemeral_5m_input_tokens": 0,
"ephemeral_1h_input_tokens": 15640
},
"type": "message"
}
],
"speed": "standard",
"fallback_credit": null
},
"modelUsage": {
"claude-opus-5-5": {
"inputTokens": 14,
"outputTokens": 5606,
"cacheReadInputTokens": 139355,
"cacheCreationInputTokens": 31280,
"webSearchRequests": 0,
"costUSD": 0.39028700000000005,
"contextWindow": 1000000,
"maxOutputTokens": 128000,
"thinkingTokens": 941,
"canonicalModel": "claude-opus-5-5",
"provider": "firstParty",
"costBasis": "list"
}
},
"permission_denials": [],
"terminal_reason": "completed",
"fast_mode_state": "off",
"fast_mode_disabled_reason": "sdk_opt_in_required",
"subagent_stats": {
"spawned": 0,
"requested": {
"background": 0,
"foreground": 0,
"unset": 0
},
"started_in_background": 0,
"max_depth": 0,
"spawned_by_subagents": 0,
"completed": 0,
"failed": 0,
"killed": {
"parent": 0,
"user": 0,
"system": 0
},
"refused": {
"depth_limit": 0,
"concurrency_limit": 0,
"budget": 0
},
"by_type": {}
},
"safety_stops": 0,
"is_error": false,
"num_turns": 7,
"subtype": "success",
"api_error_status": null,
"result": "I wrote `solve.py` (standard library only) and ran it on the given log: `python3 solve.py input.json answer.json`. It decoded 111 messages and wrote `answer.json`. I can't run the hidden checks, so I don't know yet whether the output scores correctly.\n\nError counts from the log:\n\n| Error | Count |\n|---|---|\n| `bad_checksum` | 12 |\n| `bad_payload_char` | 7 |\n| `short_message` | 7 |\n| `bad_fields` | 6 |\n| `not_ais` | 5 |\n| `unsupported_type` | 4 |\n| `bad_tag_block` | 3 |\n| `orphan_fragment` | 3 |\n| `incomplete_multipart` | 2 |\n\n**Where the spec was unclear, I picked:**\n- **Invalid payload characters:** the script checks for these after a multipart message is fully assembled, not as each fragment arrives. In this log all 7 bad-character lines are single-part, so it makes no difference here. It could matter in the fresh logs if a bad character turns up inside a multipart fragment.\n- **Very short payloads:** if a payload is too short to hold an MMSI, the script reports `unsupported_type` when the message type is unknown, and `short_message` otherwise.\n- **Lines that aren't AIS:** a line that fails only because it isn't AIS (such as the `$GPGGA` lines) still updates the current time, since it reaches the sentence stage. A line with a bad tag block doesn't update it.",
"ttft_ms": 2215,
"type": "result",
"duration_ms": 180222,
"uuid": "[REDACTED]",
"ttft_stream_ms": 940,
"time_to_request_ms": 261,
"first_content_frame_ms": 940,
"queued_turn_count": 0,
"result_index": 0
}
]