Skip to content

Commit a17ac74

Browse files
committed
feat(char): D-561 — Character/getName + codePointOf over the generated UCD name table
Smell-audited: 2: the first fixed-width index cost +394KB and was reworked to a delta-varint wire form BEFORE landing (measure-first, ADR-0172 discipline); final delta mac +279KB (7.35MB) with the README claim moved to "about 7.8 MB" and the ADR-0172 revision noting Linux at ~94% of ceiling (next size-relevant work measures Linux first). - scripts/gen_unicode_names.py: UCD 16.0.0 → word-indexed name table (40,013 per-cp names; frequency-ordered dict; CPHEX sentinel folds the hex-suffixed families' own-hex tokens out of the dictionary; pre-compressed raw-deflate blobs — matches the runtime's flate; the index is a delta-varint stream decoded once into fixed records). - src/runtime/char_name.zig: process-lifetime lazy tables + JVM-oracle- exact semantics — stored names; pinned control aliases (scripts/data/jvm_control_names.txt, captured from live clj 1.12: the JVM mixes control-type aliases with abbreviations, 0x01="START OF HEADING" but 0x07="BEL"); assigned-but-unnamed = "<BLOCK NAME> <HEX>" ("TANGUT 17000" — the JVM does NOT synthesize UCD algorithmic names); unassigned nil. codePointOf = trimmed case-insensitive inverse accepting exactly getName's output forms (block-hex confirmed by forward equality; "HANGUL SYLLABLE GA" rejected like the JVM). - Character.zig: getName realized (the last feature_not_supported stub on the class), codePointOf added; compat_tiers row updated (the member gate enforced it). Corpus char_names.txt 10/10; unit tests on the oracle values incl. controls + block-hex + unassigned. - D-561 discharged (active -> discharged).
1 parent e711c0f commit a17ac74

10 files changed

Lines changed: 1100 additions & 29 deletions

File tree

‎.dev/debt.yaml‎

Lines changed: 6 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -49,24 +49,6 @@ active:
4949
lastModified/renameTo/createNewFile set, Locale getters, Matcher
5050
region/replace family).
5151
last_reviewed: "2026-07-17"
52-
- id: "D-561"
53-
status: |-
54-
open (2026-07-15, Character/* completion cycle). `Character/getName` is
55-
the ONE java.lang.Character static not carried (explicit
56-
feature_not_supported raise; every other static method + field landed
57-
full-Unicode via the generated UCD tables — gen_unicode_case.py).
58-
getName needs the UnicodeData col-1 NAME table: raw ~1MB for ~40K
59-
non-algorithmic names; the JVM ships it word-indexed at ~90KB. DISCHARGE
60-
SHAPE: extend gen_unicode_case.py with a word-dictionary encoding
61-
(names → word-index sequences + algorithmic CJK/Hangul/Tangut ranges),
62-
decode in a new charset helper; JVM parity incl. nil for unassigned.
63-
Weigh the ~100-200KB binary cost against gap area II (Wasm/edge binary
64-
size) before landing — if the cost is judged not worth it, re-classify
65-
as an AD-NNN accepted divergence instead (the raise is explicit, not
66-
silent).
67-
category: "host-surface"
68-
barrier: "none — implementable any time; the open question is the binary-size trade (gap area II), not a technical blocker"
69-
last_reviewed: "2026-07-15"
7052
- id: "D-560"
7153
status: |-
7254
open (2026-07-13, ADR-0150 am1 accepted-cost row). The D-559 fix (the
@@ -2394,6 +2376,12 @@ standing:
23942376
barrier: "open after the D-440 arc completes (R4 + R5 must first rewrite the bulk of 'Phase N' citations to gap-area terms). Premature adoption = ~70 dangling citations with no 1:1 redirect. Trigger: D-440 R4/R5 done + a user nod to re-architect the planning axis (it is depth-4, the project's organizing metaphor)."
23952377
last_reviewed: "2026-06-15"
23962378
discharged:
2379+
- id: "D-561"
2380+
status: |-
2381+
DISCHARGED 2026-07-17 — Character/getName + codePointOf land on the generated UCD 16.0.0 word-indexed name table (scripts/gen_unicode_names.py → unicode_names.zig, pre-compressed raw-deflate blobs + delta-varint index, decoded once per process in char_name.zig). JVM-oracle-exact semantics: stored names, pinned control aliases (scripts/data/jvm_control_names.txt), assigned-but-unnamed = "<BLOCK> <HEX>" (the JVM does NOT synthesize UCD algorithmic names), unassigned nil; codePointOf = trimmed case-insensitive inverse accepting exactly getName output forms. Corpus char_names.txt 10/10. Size: mac +279KB (7.35MB; ADR-0172 revision — README claim 7.8MB; Linux ~94% of ceiling, next size work measures Linux first).
2382+
category: "host-surface"
2383+
barrier: "none — implementable any time; the open question is the binary-size trade (gap area II), not a technical blocker"
2384+
last_reviewed: "2026-07-17"
23972385
- id: "D-563"
23982386
status: |-
23992387
DISCHARGED 2026-07-17 (all sub-items resolved: a/a2/b/c landed, d = AD-043). ORIGINAL: open (2026-07-16, the D-562 inventory's enumerated residuals — each
@@ -6607,7 +6595,6 @@ discharged:
66076595
decompress); varint operands + cross-region constant-pool dedup evaluated in
66086596
the same pass (compaction shrinks with NO decompression copy). est -0.9-1.1MB.
66096597
last_reviewed: "2026-07-16"
6610-
66116598
conventions: |-
66126599
- Structure: two top-level lists — `active:` and `discharged:`. Active entries carry id / status / category / barrier (+ optional quality_floor / last_reviewed); discharged entries carry id / discharged_at / resolution. Edit as YAML (no Markdown table to align).
66136600
- New debt: grep `.dev/debt.yaml` for class-overlap before adding (per `.claude/rules/debt_dedup.md`).

‎.dev/decisions/0172_binary_size_budget_and_ledger.md‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -406,6 +406,16 @@ dispositions grounded, platform binding declared, peer number measured).
406406

407407
## Revision history
408408

409+
- **2026-07-17 (D-561 Unicode name table, conscious)**: `Character/getName`
410+
+ `codePointOf` land the full UCD 16.0.0 name table as pre-compressed
411+
word-indexed blobs (40,013 names; 545 KB raw → ~280 KB stored after the
412+
delta-varint index rework — the first fixed-width index cost +394 KB and
413+
was reworked before landing). macOS 7,073,240 → 7,352,376 B (+279 KB);
414+
Linux est. ~8.29 MB (~94% of ceiling — the NEXT size-relevant feature
415+
must measure Linux first and likely needs a lever or a ceiling
416+
amendment). README claim moved 7.5 → "about 7.8 MB" (covers both
417+
platforms within the ±10% gate).
418+
409419
- **2026-07-17 (ADR-0174 feature growth, conscious)**: the host-class
410420
identity & member-surface campaign grew the binary macOS
411421
6,974,584 → 7,073,240 B (+98.7 KB — Thread lifecycle worker + stdio

‎README.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ still use what other languages have already built.
3333

3434
## Features
3535

36-
- **Small and quick to start** — one static binary of about 7.5 MB with the
36+
- **Small and quick to start** — one static binary of about 7.8 MB with the
3737
Wasm JIT engine included (for scale: babashka's native binary is ~71 MB;
3838
[measured comparison](docs/works/binary_size.md)), starting in ~5 ms, which
3939
suits short-lived, start-and-stop workloads (CLI tools, serverless, scripts).

‎data/compat_tiers.yaml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ tiers:
195195
# 16.0.0 tables; corpus test/diff/clj_corpus/character.txt locks
196196
# clj parity). getName is explicit-unsupported (D-561). Instance
197197
# methods on .char: charValue / compareTo (+ universal Object).
198-
methods: [charCount, charValue, codePointAt, codePointBefore, codePointCount, compare, compareTo, digit, forDigit, getDirectionality, getName, getNumericValue, getType, highSurrogate, isAlphabetic, isBmpCodePoint, isDefined, isDigit, isEmoji, isEmojiComponent, isEmojiModifier, isEmojiModifierBase, isEmojiPresentation, isExtendedPictographic, isHighSurrogate, isISOControl, isIdentifierIgnorable, isIdeographic, isJavaIdentifierPart, isJavaIdentifierStart, isJavaLetter, isJavaLetterOrDigit, isLetter, isLetterOrDigit, isLowSurrogate, isLowerCase, isMirrored, isSpace, isSpaceChar, isSupplementaryCodePoint, isSurrogate, isSurrogatePair, isTitleCase, isUnicodeIdentifierPart, isUnicodeIdentifierStart, isUpperCase, isValidCodePoint, isWhitespace, lowSurrogate, offsetByCodePoints, reverseBytes, toChars, toCodePoint, toLowerCase, toTitleCase, toUpperCase, valueOf]
198+
methods: [charCount, charValue, codePointAt, codePointBefore, codePointCount, codePointOf, compare, compareTo, digit, forDigit, getDirectionality, getName, getNumericValue, getType, highSurrogate, isAlphabetic, isBmpCodePoint, isDefined, isDigit, isEmoji, isEmojiComponent, isEmojiModifier, isEmojiModifierBase, isEmojiPresentation, isExtendedPictographic, isHighSurrogate, isISOControl, isIdentifierIgnorable, isIdeographic, isJavaIdentifierPart, isJavaIdentifierStart, isJavaLetter, isJavaLetterOrDigit, isLetter, isLetterOrDigit, isLowSurrogate, isLowerCase, isMirrored, isSpace, isSpaceChar, isSupplementaryCodePoint, isSurrogate, isSurrogatePair, isTitleCase, isUnicodeIdentifierPart, isUnicodeIdentifierStart, isUpperCase, isValidCodePoint, isWhitespace, lowSurrogate, offsetByCodePoints, reverseBytes, toChars, toCodePoint, toLowerCase, toTitleCase, toUpperCase, valueOf]
199199
static_fields: ["BYTES", "COMBINING_SPACING_MARK", "CONNECTOR_PUNCTUATION", "CONTROL", "CURRENCY_SYMBOL", "DASH_PUNCTUATION", "DECIMAL_DIGIT_NUMBER", "DIRECTIONALITY_ARABIC_NUMBER", "DIRECTIONALITY_BOUNDARY_NEUTRAL", "DIRECTIONALITY_COMMON_NUMBER_SEPARATOR", "DIRECTIONALITY_EUROPEAN_NUMBER", "DIRECTIONALITY_EUROPEAN_NUMBER_SEPARATOR", "DIRECTIONALITY_EUROPEAN_NUMBER_TERMINATOR", "DIRECTIONALITY_FIRST_STRONG_ISOLATE", "DIRECTIONALITY_LEFT_TO_RIGHT", "DIRECTIONALITY_LEFT_TO_RIGHT_EMBEDDING", "DIRECTIONALITY_LEFT_TO_RIGHT_ISOLATE", "DIRECTIONALITY_LEFT_TO_RIGHT_OVERRIDE", "DIRECTIONALITY_NONSPACING_MARK", "DIRECTIONALITY_OTHER_NEUTRALS", "DIRECTIONALITY_PARAGRAPH_SEPARATOR", "DIRECTIONALITY_POP_DIRECTIONAL_FORMAT", "DIRECTIONALITY_POP_DIRECTIONAL_ISOLATE", "DIRECTIONALITY_RIGHT_TO_LEFT", "DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC", "DIRECTIONALITY_RIGHT_TO_LEFT_EMBEDDING", "DIRECTIONALITY_RIGHT_TO_LEFT_ISOLATE", "DIRECTIONALITY_RIGHT_TO_LEFT_OVERRIDE", "DIRECTIONALITY_SEGMENT_SEPARATOR", "DIRECTIONALITY_UNDEFINED", "DIRECTIONALITY_WHITESPACE", "ENCLOSING_MARK", "END_PUNCTUATION", "FINAL_QUOTE_PUNCTUATION", "FORMAT", "INITIAL_QUOTE_PUNCTUATION", "LETTER_NUMBER", "LINE_SEPARATOR", "LOWERCASE_LETTER", "MATH_SYMBOL", "MAX_CODE_POINT", "MAX_HIGH_SURROGATE", "MAX_LOW_SURROGATE", "MAX_RADIX", "MAX_SURROGATE", "MAX_VALUE", "MIN_CODE_POINT", "MIN_HIGH_SURROGATE", "MIN_LOW_SURROGATE", "MIN_RADIX", "MIN_SUPPLEMENTARY_CODE_POINT", "MIN_SURROGATE", "MIN_VALUE", "MODIFIER_LETTER", "MODIFIER_SYMBOL", "NON_SPACING_MARK", "OTHER_LETTER", "OTHER_NUMBER", "OTHER_PUNCTUATION", "OTHER_SYMBOL", "PARAGRAPH_SEPARATOR", "PRIVATE_USE", "SIZE", "SPACE_SEPARATOR", "START_PUNCTUATION", "SURROGATE", "TITLECASE_LETTER", "UNASSIGNED", "UPPERCASE_LETTER"]
200200
opaque_members: [TYPE]
201201
clojure_peer_vars: []

‎scripts/data/jvm_control_names.txt‎

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
# JVM Character.getName oracle for control codepoints (clj 1.12, captured 2026-07-17).
2+
# Pinned rather than re-deriving NameAliases.txt's preference rule (JVM mixes
3+
# control-type aliases with abbreviations: 0x07=BEL but 0x01=START OF HEADING).
4+
0 NULL
5+
1 START OF HEADING
6+
2 START OF TEXT
7+
3 END OF TEXT
8+
4 END OF TRANSMISSION
9+
5 ENQUIRY
10+
6 ACKNOWLEDGE
11+
7 BEL
12+
8 BACKSPACE
13+
9 CHARACTER TABULATION
14+
10 LINE FEED (LF)
15+
11 LINE TABULATION
16+
12 FORM FEED (FF)
17+
13 CARRIAGE RETURN (CR)
18+
14 SHIFT OUT
19+
15 SHIFT IN
20+
16 DATA LINK ESCAPE
21+
17 DEVICE CONTROL ONE
22+
18 DEVICE CONTROL TWO
23+
19 DEVICE CONTROL THREE
24+
20 DEVICE CONTROL FOUR
25+
21 NEGATIVE ACKNOWLEDGE
26+
22 SYNCHRONOUS IDLE
27+
23 END OF TRANSMISSION BLOCK
28+
24 CANCEL
29+
25 END OF MEDIUM
30+
26 SUBSTITUTE
31+
27 ESCAPE
32+
28 INFORMATION SEPARATOR FOUR
33+
29 INFORMATION SEPARATOR THREE
34+
30 INFORMATION SEPARATOR TWO
35+
31 INFORMATION SEPARATOR ONE
36+
32 SPACE
37+
127 DELETE
38+
128 PADDING CHARACTER
39+
129 HIGH OCTET PRESET
40+
130 BREAK PERMITTED HERE
41+
131 NO BREAK HERE
42+
132 LATIN 1 SUPPLEMENT 84
43+
133 NEXT LINE (NEL)
44+
134 START OF SELECTED AREA
45+
135 END OF SELECTED AREA
46+
136 CHARACTER TABULATION SET
47+
137 CHARACTER TABULATION WITH JUSTIFICATION
48+
138 LINE TABULATION SET
49+
139 PARTIAL LINE FORWARD
50+
140 PARTIAL LINE BACKWARD
51+
141 REVERSE LINE FEED
52+
142 SINGLE SHIFT TWO
53+
143 SINGLE SHIFT THREE
54+
144 DEVICE CONTROL STRING
55+
145 PRIVATE USE ONE
56+
146 PRIVATE USE TWO
57+
147 SET TRANSMIT STATE
58+
148 CANCEL CHARACTER
59+
149 MESSAGE WAITING
60+
150 START OF GUARDED AREA
61+
151 END OF GUARDED AREA
62+
152 START OF STRING
63+
153 SINGLE GRAPHIC CHARACTER INTRODUCER
64+
154 SINGLE CHARACTER INTRODUCER
65+
155 CONTROL SEQUENCE INTRODUCER
66+
156 STRING TERMINATOR
67+
157 OPERATING SYSTEM COMMAND
68+
158 PRIVACY MESSAGE
69+
159 APPLICATION PROGRAM COMMAND
70+
160 NO-BREAK SPACE

0 commit comments

Comments
 (0)