Claude Haiku 5.5 (effort default (no --effort flag) · thinking on) on Unicode-correct username canonicalisation (NFKC, casefold, mixed-script), terminal width, cluster-safe truncation and slugs
AClaude Haiku 5.5default · thinking on · Claude Code 2.1.299 (headless -p) · cloud · 2026-10-17 · by @bobsiopener
- Estimated cost
- $0.01
- Wall time
- 1m
- Human step-ins
- 0
- Outcome
- Pass
Compare with other models on this task →
Summary
Exact prompt
# Task: make the text helpers Unicode-correct Rewrite the four functions in `textnorm.py` (Python stdlib only, `unicodedata` is fine) to these rules: **canonical_username(s)** - used to detect duplicate/impersonating accounts. 1. Remove zero-width/format characters U+200B, U+200C, U+200D, U+2060, U+FEFF and U+00AD (soft hyphen); apply NFKC; casefold (Python `str.casefold()`; note it maps a Greek final sigma ς to σ, so `"Δημήτρης"` -> `"δημήτρησ"`); strip surrounding whitespace. 2. The result must be 3-32 characters, contain only letters (any script, category L*), digits (Nd), `.`, `_`, `-`, and must not mix scripts: all letters must come from one script among Latin, Greek, Cyrillic (judge by `unicodedata.name` starting with `LATIN`, `GREEK`, `CYRILLIC`; letters from any other script are allowed only if all letters are from that same other script, judged by the first word of the name). Otherwise raise `ValueError`. Examples: `" John_Doe "` -> `"john_doe"`; `"STRASSE"` and `"straße"` both -> `"strasse"`; `"pаypal"` (Cyrillic а) -> ValueError. **display_width(s)** - terminal columns: characters with East Asian Width `W` or `F` count 2; combining marks (categories Mn, Me), format chars (Cf) and the zero-width chars above count 0; control characters (Cc) count 0; everything else 1 (so East Asian Width `A`/`N`/`Na`/`H` count 1: `…` is 1, `❤` is 1, each regional-indicator letter is 1 so a flag pair is 2, and U+FE0F is 0 as a combining mark). **truncate(s, width, ellipsis="…")** - if `display_width(s) <= width` return `s` unchanged. Otherwise return the longest prefix such that display_width(prefix) + display_width(ellipsis) <= `width`, never splitting a base character from its following combining marks/ZWJ/variation selectors (U+FE00-FE0F), never splitting a regional-indicator pair (flag) and never leaving a dangling ZWJ (U+200D) at the end of the prefix. Then append ellipsis. If even the ellipsis doesn't fit, return "". **slugify(s)** - NFKD, drop combining marks, map `ß`->`ss`, `æ`->`ae`, `œ`->`oe`, `ø`->`o`, `ł`->`l`, `đ`->`d`, `þ`->`th` (and their uppercase forms), lowercase, then every run of characters other than `a-z0-9` becomes a single `-`; strip leading/trailing `-`. If longer than 60 characters, cut to 60 and then, if the cut fell inside a word (the 60th and 61st characters are both letters/digits), back off to the last `-` within the 60 (when there is one); finally strip trailing `-`. Examples: 20 x "word " -> 12 x "word" joined by `-`; `"abc " + 70 x "y"` -> `"abc"`; 70 x "x" -> 60 x "x". Empty result -> `"n-a"`. No network.
Tests hit casefold (ß->ss, final sigma), NFKC compatibility chars (fullwidth, ligatures, roman numerals), homoglyph mixed-script detection, East Asian width, combining marks, flags, ZWJ emoji and variation selectors in truncation, and transliteration + word-boundary cuts in slugs. 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. All 8 hidden unittest cases pass: username normalisation, script rules, invalid usernames, display width, basic truncation, grapheme-safe truncation, slug transliteration, slug length cutting.
Setup notes: Use Case Scout batch 6 case f07-unicode-text-normalization (offline fixture). Prepared with batch6/prepare.sh; hidden key/tests kept outside the agent's work dir. Prompt = TASK.md verbatim. Scored with the scout's scorer: `python score.py WORKDIR KEYDIR`. Tools: Read/Write/Edit/Glob/Grep/Bash, web disabled. Single run, no retries. Claude Code's own reported cost for claude-haiku-5.5: $0.012571. Score: 8/8. 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.01
- Wall time
- 1m
- Human step-ins
- 0
- Turns
- 5
| Model | Input tok | Output tok | Cost |
|---|---|---|---|
| AClaude Haiku 5.5anthropic/claude-haiku-5.5effort default (no --effort flag) · thinking on | 128,757 | 14,277 | $0.01 |
Reproduce this run
- Use the use case prompt on the use case page.
- Same setup: Claude Haiku 5.5 (anthropic/claude-haiku-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. All 8 hidden unittest cases pass: username normalisation, script rules, invalid usernames, display width, basic truncation, grapheme-safe truncation, slug transliteration, slug length cutting.
- 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": 65839,
"stop_reason": "end_turn",
"session_id": "[REDACTED]",
"total_cost_usd": 0.01257087,
"usage": {
"input_tokens": 10,
"cache_creation_input_tokens": 21810,
"cache_read_input_tokens": 106937,
"output_tokens": 14277,
"output_tokens_details": {
"thinking_tokens": 10544
},
"server_tool_use": {
"web_search_requests": 0,
"web_fetch_requests": 0
},
"service_tier": "standard",
"cache_creation": {
"ephemeral_1h_input_tokens": 21810,
"ephemeral_5m_input_tokens": 0
},
"inference_geo": "global",
"iterations": [
{
"input_tokens": 2,
"output_tokens": 1358,
"cache_read_input_tokens": 32894,
"cache_creation_input_tokens": 1455,
"cache_creation": {
"ephemeral_5m_input_tokens": 0,
"ephemeral_1h_input_tokens": 1455
},
"type": "message"
}
],
"speed": "standard",
"fallback_credit": null
},
"modelUsage": {
"claude-haiku-5-5": {
"inputTokens": 10,
"outputTokens": 14277,
"cacheReadInputTokens": 106937,
"cacheCreationInputTokens": 21810,
"webSearchRequests": 0,
"costUSD": 0.01257087,
"contextWindow": 1000000,
"maxOutputTokens": 128000,
"thinkingTokens": 10544,
"canonicalModel": "claude-haiku-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": 5,
"subtype": "success",
"api_error_status": null,
"result": "I rewrote all four functions in `textnorm.py` to the spec. The spec examples pass in ad-hoc checks run against the file. I didn't add a test file to the work directory.\n\nWhat changed:\n\n- **`canonical_username`**: strips the listed format characters, applies NFKC and casefold, then strips whitespace. It checks length (3\u201332), allows only L*, Nd, `.`, `_`, `-`, and raises `ValueError` if letters come from more than one script (judged by the first word of `unicodedata.name`).\n- **`display_width`**: 0 for Mn, Me, Cf and Cc; 2 for East Asian Width W or F; 1 otherwise.\n- **`truncate`**: splits the string into clusters (base character plus marks, variation selectors and ZWJ-joined next character, and regional-indicator pairs), keeps whole clusters that fit, strips any trailing ZWJ, then appends the ellipsis. It returns `\"\"` if the ellipsis alone doesn't fit.\n- **`slugify`**: applies NFKD, drops marks, maps the listed letters (and uppercase forms), lowercases, collapses non-`a-z0-9` runs to `-`, and applies the 60-character word-boundary rule and the `\"n-a\"` fallback.\n\nChoices I made where the spec was silent or ambiguous:\n\n- **Digits-only usernames** such as `\"123\"` are allowed, since no letters means no script conflict.\n- **Slugify marks**: lowercasing can reintroduce a combining mark (`\"\u0130\"` becomes `i` plus U+0307), so I strip marks a second time after lowercasing. Without this, `\"\u0130\"` would become a `-` separator.\n- **Emoji ZWJ sequences** are treated as one unit, so `truncate` never cuts inside a family emoji.\n- **Mc (spacing combining marks)** attach to their base in `truncate`, though they count as width 1 like any other non-zero character.\n\nSpec-literal behaviours you may want to change:\n\n- Letters like `\u00f0` and dotless `\u0131` are not in the slug map, so they become `-`.\n- Modifier letters (category Lm) are judged by their name's first word, for example `MODIFIER`, so mixing one with Latin raises `ValueError`.\n\nThis directory is not a git repository, so I did not commit anything.",
"ttft_ms": 1744,
"type": "result",
"duration_ms": 66269,
"uuid": "[REDACTED]",
"ttft_stream_ms": 1550,
"time_to_request_ms": 289,
"first_content_frame_ms": 1551,
"queued_turn_count": 0,
"result_index": 0
}
]