ucode 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (174) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +72 -0
  3. data/Gemfile.lock +2 -2
  4. data/TODO.full/00-README.md +116 -0
  5. data/TODO.full/01-panglyph-vision.md +112 -0
  6. data/TODO.full/02-panglyph-repo-bootstrap.md +184 -0
  7. data/TODO.full/03-panglyph-font-builder.md +201 -0
  8. data/TODO.full/04-panglyph-publish-pipeline.md +126 -0
  9. data/TODO.full/05-ucode-0-1-1-release.md +139 -0
  10. data/TODO.full/06-fontisan-remove-audit.md +142 -0
  11. data/TODO.full/07-fontisan-remove-ucd.md +125 -0
  12. data/TODO.full/08-archive-private-bin-build.md +143 -0
  13. data/TODO.full/09-archive-public-structure.md +164 -0
  14. data/TODO.full/10-fontist-org-woff-glyphs.md +131 -0
  15. data/TODO.full/11-fontist-org-audit-coverage.md +140 -0
  16. data/TODO.full/12-implementation-order.md +216 -0
  17. data/TODO.full/13-fontisan-font-writer-api.md +189 -0
  18. data/TODO.full/14-fontisan-table-writers.md +66 -0
  19. data/TODO.full/15-panglyph-builder-real.md +82 -0
  20. data/TODO.full/16-archive-public-sync-workflows.md +167 -0
  21. data/TODO.full/17-fontist-org-font-picker.md +73 -0
  22. data/TODO.full/18-comprehensive-spec-coverage.md +64 -0
  23. data/TODO.full/19-ucode-0-1-2-patch.md +32 -0
  24. data/TODO.full/20-fontisan-0-2-23-release.md +52 -0
  25. data/TODO.new/00-README.md +30 -0
  26. data/TODO.new/23-universal-glyph-set-source-map.md +312 -0
  27. data/TODO.new/24-universal-glyph-set-build.md +189 -0
  28. data/TODO.new/25-font-audit-against-universal-set.md +195 -0
  29. data/TODO.new/26-missing-glyph-reporter.md +189 -0
  30. data/TODO.new/27-fontist-org-consumer-integration.md +200 -0
  31. data/TODO.new/28-implementation-order-update.md +187 -0
  32. data/TODO.new/29-universal-set-curation-uc17.md +312 -0
  33. data/TODO.new/30-tier1-font-acquisition.md +241 -0
  34. data/TODO.new/31-universal-set-production-build.md +205 -0
  35. data/TODO.new/32-uc17-coverage-matrix.md +165 -0
  36. data/TODO.new/33-specialist-font-acquisition-refresh.md +138 -0
  37. data/TODO.new/34-pillar2-content-stream-correlator.md +147 -0
  38. data/TODO.new/35-universal-set-production-run.md +160 -0
  39. data/TODO.new/36-per-font-coverage-audit.md +145 -0
  40. data/TODO.new/37-coverage-highlight-reporter.md +125 -0
  41. data/TODO.new/38-fontist-org-glyph-consumer.md +141 -0
  42. data/TODO.new/39-implementation-order-update-32-38.md +258 -0
  43. data/TODO.new/40-archive-private-uses-ucode-audit.md +124 -0
  44. data/TODO.new/41-ucode-unicode-archive-bridge.md +160 -0
  45. data/config/specialist_fonts.yml +102 -0
  46. data/config/unicode17_tier1_fonts.yml +42 -0
  47. data/config/unicode17_universal_glyph_set.yml +293 -0
  48. data/lib/ucode/audit/block_aggregator.rb +57 -29
  49. data/lib/ucode/audit/browser/face_page.rb +128 -0
  50. data/lib/ucode/audit/browser/glyph_panel.rb +124 -0
  51. data/lib/ucode/audit/browser/library_page.rb +74 -0
  52. data/lib/ucode/audit/browser/missing_glyph_page.rb +87 -0
  53. data/lib/ucode/audit/browser/template.rb +47 -0
  54. data/lib/ucode/audit/browser/templates/face.css +200 -0
  55. data/lib/ucode/audit/browser/templates/face.html.erb +41 -0
  56. data/lib/ucode/audit/browser/templates/face.js +298 -0
  57. data/lib/ucode/audit/browser/templates/library.css +119 -0
  58. data/lib/ucode/audit/browser/templates/library.html.erb +42 -0
  59. data/lib/ucode/audit/browser/templates/library.js +99 -0
  60. data/lib/ucode/audit/browser/templates/missing_glyph_page.css +119 -0
  61. data/lib/ucode/audit/browser/templates/missing_glyph_page.html.erb +58 -0
  62. data/lib/ucode/audit/browser/templates/missing_glyph_page.js +2 -0
  63. data/lib/ucode/audit/browser.rb +32 -0
  64. data/lib/ucode/audit/context.rb +27 -1
  65. data/lib/ucode/audit/coverage_reference.rb +103 -0
  66. data/lib/ucode/audit/differ.rb +121 -0
  67. data/lib/ucode/audit/emitter/block_emitter.rb +52 -0
  68. data/lib/ucode/audit/emitter/codepoint_emitter.rb +87 -0
  69. data/lib/ucode/audit/emitter/collection_emitter.rb +80 -0
  70. data/lib/ucode/audit/emitter/face_directory.rb +212 -0
  71. data/lib/ucode/audit/emitter/glyph_emitter.rb +48 -0
  72. data/lib/ucode/audit/emitter/index_emitter.rb +149 -0
  73. data/lib/ucode/audit/emitter/library_emitter.rb +96 -0
  74. data/lib/ucode/audit/emitter/paths.rb +312 -0
  75. data/lib/ucode/audit/emitter/plane_emitter.rb +29 -0
  76. data/lib/ucode/audit/emitter/script_emitter.rb +29 -0
  77. data/lib/ucode/audit/emitter.rb +29 -0
  78. data/lib/ucode/audit/extractors/aggregations.rb +31 -2
  79. data/lib/ucode/audit/face_auditor.rb +86 -0
  80. data/lib/ucode/audit/formatters/audit_diff_text.rb +112 -0
  81. data/lib/ucode/audit/formatters/audit_text.rb +411 -0
  82. data/lib/ucode/audit/formatters/color.rb +48 -0
  83. data/lib/ucode/audit/formatters/library_summary_text.rb +98 -0
  84. data/lib/ucode/audit/formatters/text_formatter.rb +83 -0
  85. data/lib/ucode/audit/formatters.rb +23 -0
  86. data/lib/ucode/audit/library_aggregator.rb +86 -0
  87. data/lib/ucode/audit/library_auditor.rb +105 -0
  88. data/lib/ucode/audit/release/emitter.rb +152 -0
  89. data/lib/ucode/audit/release/face_card.rb +93 -0
  90. data/lib/ucode/audit/release/formula_audits.rb +50 -0
  91. data/lib/ucode/audit/release/library_index_builder.rb +78 -0
  92. data/lib/ucode/audit/release/manifest_builder.rb +127 -0
  93. data/lib/ucode/audit/release.rb +42 -0
  94. data/lib/ucode/audit/ucd_only_reference.rb +81 -0
  95. data/lib/ucode/audit/universal_set_reference.rb +136 -0
  96. data/lib/ucode/audit.rb +31 -0
  97. data/lib/ucode/cli.rb +339 -33
  98. data/lib/ucode/commands/audit/browser_command.rb +82 -0
  99. data/lib/ucode/commands/audit/collection_command.rb +103 -0
  100. data/lib/ucode/commands/audit/compare_command.rb +188 -0
  101. data/lib/ucode/commands/audit/font_command.rb +140 -0
  102. data/lib/ucode/commands/audit/library_command.rb +87 -0
  103. data/lib/ucode/commands/audit/reference_builder.rb +64 -0
  104. data/lib/ucode/commands/audit.rb +20 -0
  105. data/lib/ucode/commands/block_feed.rb +73 -0
  106. data/lib/ucode/commands/canonical_build.rb +138 -0
  107. data/lib/ucode/commands/fetch.rb +37 -1
  108. data/lib/ucode/commands/release.rb +115 -0
  109. data/lib/ucode/commands/universal_set.rb +211 -0
  110. data/lib/ucode/commands.rb +5 -0
  111. data/lib/ucode/coordinator/indices.rb +11 -0
  112. data/lib/ucode/coordinator.rb +138 -5
  113. data/lib/ucode/error.rb +30 -2
  114. data/lib/ucode/fetch/font_fetcher/result.rb +39 -0
  115. data/lib/ucode/fetch/font_fetcher.rb +16 -0
  116. data/lib/ucode/fetch/specialist_font_fetcher.rb +280 -0
  117. data/lib/ucode/fetch.rb +7 -3
  118. data/lib/ucode/glyphs/real_fonts/cmap_cache.rb +74 -0
  119. data/lib/ucode/glyphs/real_fonts.rb +1 -0
  120. data/lib/ucode/glyphs/resolver.rb +62 -0
  121. data/lib/ucode/glyphs/source.rb +48 -0
  122. data/lib/ucode/glyphs/source_builder.rb +61 -0
  123. data/lib/ucode/glyphs/source_config/coverage_assertion.rb +79 -0
  124. data/lib/ucode/glyphs/source_config/gap_report.rb +54 -0
  125. data/lib/ucode/glyphs/source_config.rb +104 -0
  126. data/lib/ucode/glyphs/sources/pillar1_embedded_tounicode.rb +63 -0
  127. data/lib/ucode/glyphs/sources/pillar3_last_resort.rb +51 -0
  128. data/lib/ucode/glyphs/sources/tier1_real_font.rb +104 -0
  129. data/lib/ucode/glyphs/sources.rb +20 -0
  130. data/lib/ucode/glyphs/universal_set/builder.rb +161 -0
  131. data/lib/ucode/glyphs/universal_set/coverage_report.rb +139 -0
  132. data/lib/ucode/glyphs/universal_set/idempotency.rb +86 -0
  133. data/lib/ucode/glyphs/universal_set/manifest_accumulator.rb +195 -0
  134. data/lib/ucode/glyphs/universal_set/manifest_writer.rb +61 -0
  135. data/lib/ucode/glyphs/universal_set/pre_build_check.rb +197 -0
  136. data/lib/ucode/glyphs/universal_set/validator.rb +204 -0
  137. data/lib/ucode/glyphs/universal_set.rb +45 -0
  138. data/lib/ucode/glyphs.rb +6 -0
  139. data/lib/ucode/models/audit/baseline.rb +6 -0
  140. data/lib/ucode/models/audit/block_summary.rb +7 -0
  141. data/lib/ucode/models/audit/codepoint_provenance.rb +39 -0
  142. data/lib/ucode/models/audit/release_face.rb +42 -0
  143. data/lib/ucode/models/audit/release_formula.rb +33 -0
  144. data/lib/ucode/models/audit/release_manifest.rb +43 -0
  145. data/lib/ucode/models/audit/release_universal_set.rb +37 -0
  146. data/lib/ucode/models/audit.rb +9 -0
  147. data/lib/ucode/models/block.rb +2 -0
  148. data/lib/ucode/models/build_report.rb +109 -0
  149. data/lib/ucode/models/codepoint/glyph.rb +42 -0
  150. data/lib/ucode/models/codepoint.rb +3 -0
  151. data/lib/ucode/models/glyph_source.rb +86 -0
  152. data/lib/ucode/models/glyph_source_map.rb +138 -0
  153. data/lib/ucode/models/specialist_font.rb +70 -0
  154. data/lib/ucode/models/specialist_font_manifest.rb +48 -0
  155. data/lib/ucode/models/unihan_entry.rb +81 -9
  156. data/lib/ucode/models/unihan_field.rb +21 -0
  157. data/lib/ucode/models/universal_set_entry.rb +47 -0
  158. data/lib/ucode/models/universal_set_manifest.rb +78 -0
  159. data/lib/ucode/models/validation_report.rb +99 -0
  160. data/lib/ucode/models.rb +9 -0
  161. data/lib/ucode/parsers/named_sequences.rb +5 -5
  162. data/lib/ucode/parsers/unihan.rb +50 -19
  163. data/lib/ucode/repo/aggregate_writer.rb +34 -2
  164. data/lib/ucode/repo/block_feed_emitter.rb +153 -0
  165. data/lib/ucode/repo/build_report_accumulator.rb +138 -0
  166. data/lib/ucode/repo/build_report_writer.rb +46 -0
  167. data/lib/ucode/repo/build_validator.rb +229 -0
  168. data/lib/ucode/repo/codepoint_writer.rb +50 -1
  169. data/lib/ucode/repo/paths.rb +8 -0
  170. data/lib/ucode/repo.rb +4 -0
  171. data/lib/ucode/version.rb +1 -1
  172. data/schema/block-feed.output.schema.yml +134 -0
  173. metadata +143 -2
  174. data/ucode.gemspec +0 -56
@@ -0,0 +1,189 @@
1
+ # 26 — Missing glyph reporter (drill-down view)
2
+
3
+ ## Goal
4
+
5
+ Per-font drill-down view that renders the universal-set glyph SVG next
6
+ to every missing codepoint. Turns "this font is missing U+10980" into
7
+ "this font is missing U+10980, here's what it looks like."
8
+
9
+ This is Part 3 of the user's three-part directive. Without it, the
10
+ audit report (TODO 25) is a list of integers; with it, the user sees
11
+ the actual glyph shape they're missing.
12
+
13
+ ## Why a separate TODO
14
+
15
+ TODO 14 (HTML face browser) shows missing codepoints as chips. TODO 26
16
+ adds a glyph rendering mode: each chip loads the universal-set SVG for
17
+ that codepoint and shows it inline.
18
+
19
+ Two different concerns:
20
+
21
+ - TODO 14: the browser shell, navigation, sortable tables, plane band.
22
+ - TODO 26: the glyph-rendering drill-down that the browser shell calls
23
+ into when the user clicks a chip.
24
+
25
+ Building TODO 26 on top of TODO 14 keeps the glyph rendering isolated
26
+ and reviewable.
27
+
28
+ ## Files to create / change
29
+
30
+ - `lib/ucode/audit/browser/glyph_panel.rb` — new component: given a
31
+ codepoint + universal-set manifest path, returns the inline SVG
32
+ markup for the panel.
33
+ - `lib/ucode/audit/browser/templates/glyph_panel.html.erb` — the panel
34
+ template (used both for inline expansion and standalone mode below).
35
+ - `lib/ucode/audit/browser/missing_glyph_page.rb` — optional standalone
36
+ per-block "missing glyphs gallery" page: emits
37
+ `output/font_audit/<label>/missing/<BLOCK>.html` per touched block.
38
+ - `lib/ucode/audit/browser/templates/missing_glyph_page.html.erb`.
39
+ - `lib/ucode/audit/browser/face_page.rb` — update to accept a
40
+ `universal_set_root:` kwarg; when present, JS hooks become
41
+ glyph-aware.
42
+ - `lib/ucode/audit/browser/templates/face.js` — add glyph-panel logic.
43
+ - Specs:
44
+ - `spec/ucode/audit/browser/glyph_panel_spec.rb`
45
+ - `spec/ucode/audit/browser/missing_glyph_page_spec.rb`
46
+ - update `face_page_spec.rb` to cover the glyph-aware mode.
47
+
48
+ ## Glyph panel shape
49
+
50
+ When the user clicks a codepoint chip (e.g. U+037D in Greek and Coptic
51
+ block, marked missing), the panel expands inline:
52
+
53
+ ```
54
+ ┌──────────────────────────────────────────────────────┐
55
+ │ U+037D GREEK SMALL LETTER PAMPHYLIAN DIGAMMA │
56
+ │ │
57
+ │ [SVG: ] │
58
+ │ [ SVG ] ← universal-set glyph rendered inline │
59
+ │ [ ] │
60
+ │ │
61
+ │ Source: tier-1:noto-sans │
62
+ │ Unicode block: Greek and Coptic │
63
+ │ Age: Unicode 5.1 (March 2008) │
64
+ │ General category: Ll (Lowercase Letter) │
65
+ │ │
66
+ │ This font is missing this codepoint. │
67
+ │ Universal glyph shown for reference. │
68
+ └──────────────────────────────────────────────────────┘
69
+ ```
70
+
71
+ The SVG comes from the universal-set directory
72
+ (`output/universal_glyph_set/glyphs/U+037D.svg`), resolved via the
73
+ manifest's per-codepoint entry.
74
+
75
+ ## Standalone missing-glyph gallery
76
+
77
+ The standalone page (`missing_glyph_page.html.erb`) emits one HTML
78
+ file per touched block, listing every missing codepoint in that block
79
+ as a grid of glyph thumbnails:
80
+
81
+ ```
82
+ output/font_audit/<label>/missing/
83
+ ├── Greek_and_Coptic.html # ~55 missing glyphs as a grid
84
+ ├── Sidetic.html # ~26 missing glyphs
85
+ └── CJK_Unified_Ideographs.html # potentially thousands
86
+ ```
87
+
88
+ The gallery is a static page — no JS needed. Each thumbnail links to
89
+ the chip in the main `index.html` (so users can jump back to context).
90
+
91
+ This page is what fontist.org can iframe or screenshot for the "what's
92
+ missing" widget.
93
+
94
+ ## JS behavior (face.js additions)
95
+
96
+ ```js
97
+ // when a codepoint chip is clicked:
98
+ async function expandCodepoint(chip, codepoint) {
99
+ const panel = await renderPanel(codepoint);
100
+ chip.insertAdjacentElement('afterend', panel);
101
+ }
102
+
103
+ async function renderPanel(codepoint) {
104
+ // 1. fetch codepoints/<BLOCK>.json → get name, gc, age, etc.
105
+ // 2. fetch ../../../universal_glyph_set/glyphs/<U+XXXX>.svg
106
+ // (path resolved from manifest field)
107
+ // 3. fetch ../../../universal_glyph_set/manifest.json → get source
108
+ // 4. build panel DOM, return
109
+ }
110
+ ```
111
+
112
+ If the universal set is not co-located with the audit output (e.g. the
113
+ audit was generated on a different machine), the page shows a "glyph
114
+ preview not available" message instead of the SVG. The page itself
115
+ remains functional.
116
+
117
+ ## Universal-set path resolution
118
+
119
+ `face_page.rb` records the universal-set path in the inlined JSON
120
+ overview:
121
+
122
+ ```json
123
+ {
124
+ ...
125
+ "universal_set": {
126
+ "available": true,
127
+ "manifest_path": "../../../universal_glyph_set/manifest.json",
128
+ "glyphs_dir": "../../../universal_glyph_set/glyphs/"
129
+ }
130
+ }
131
+ ```
132
+
133
+ The JS uses these paths at runtime. When `available: false`, the JS
134
+ skips the SVG fetch and shows the text-only panel.
135
+
136
+ ## Standalone page generation
137
+
138
+ The standalone missing-glyph page is opt-in:
139
+
140
+ ```bash
141
+ bin/ucode audit font <path> --with-missing-glyph-pages
142
+ ```
143
+
144
+ This flag implies `--with-glyphs` (TODO 14's verbose flag) and
145
+ requires a universal-set manifest to be present. Output goes under
146
+ `output/font_audit/<label>/missing/<BLOCK>.html` per touched block.
147
+
148
+ ## Performance considerations
149
+
150
+ - A CJK font can be missing thousands of codepoints. The grid is
151
+ paginated client-side (50 per page); the static HTML emits only the
152
+ first page; subsequent pages are loaded via fetch from a parallel
153
+ JSON file (`missing/<BLOCK>.json`).
154
+ - The SVG fetch is cached per session (Map); clicking the same
155
+ codepoint twice doesn't re-fetch.
156
+ - For very large blocks (CJK), the standalone page emits at most 500
157
+ thumbnails; the rest are available via the JSON file.
158
+
159
+ ## Acceptance
160
+
161
+ - Clicking a missing-codepoint chip on the face page opens a panel
162
+ that renders the universal-set glyph SVG inline.
163
+ - The panel shows: codepoint id, name, age, gc, block, universal-set
164
+ source provenance, "this font is missing this codepoint" notice.
165
+ - `--with-missing-glyph-pages` produces per-block standalone HTML
166
+ files at `output/font_audit/<label>/missing/<BLOCK>.html`.
167
+ - When the universal set is not co-located, the panel shows a
168
+ text-only fallback without errors.
169
+ - The standalone gallery page is self-contained (inlined CSS/JS);
170
+ works via `file://`.
171
+ - Specs cover: panel rendering with SVG, panel rendering without SVG,
172
+ standalone gallery generation, pagination.
173
+ - Rubocop clean.
174
+
175
+ ## Out of scope
176
+
177
+ - The face browser shell itself — TODO 14.
178
+ - The library browser (cross-font view) — TODO 15.
179
+ - fontist.org consumer side — TODO 27.
180
+ - The universal-set build — TODO 24.
181
+
182
+ ## References
183
+
184
+ - Universal set build: `TODO.new/24-universal-glyph-set-build.md`
185
+ - Font audit against universal set: `TODO.new/25-font-audit-against-universal-set.md`
186
+ - HTML face browser: `TODO.new/14-html-face-browser.md`
187
+ - fontist.org contract: `TODO.new/04-fontist-org-contract.md`
188
+ - Existing face browser: `lib/ucode/audit/browser/face_page.rb`
189
+ (post-TODO 14)
@@ -0,0 +1,200 @@
1
+ # 27 — fontist.org consumer integration
2
+
3
+ ## Goal
4
+
5
+ Wire fontist.org (the consumer side) to ingest ucode's per-font audit
6
+ JSON + universal-set glyph references. Replaces the current
7
+ fontisan-YAML consumer with the new ucode-JSON consumer defined in
8
+ TODO 04.
9
+
10
+ This is the "fully integrate with fontist.org" directive. Two repos
11
+ are touched:
12
+
13
+ - `fontist/ucode` (this repo) — produces the artifacts.
14
+ - `fontist/fontist.org` (consumer) — fetches and renders them.
15
+
16
+ The contract is locked in TODO 04; this TODO implements the consumer
17
+ side and any producer-side emitter gaps the consumer surfaces.
18
+
19
+ ## What exists today (consumer side)
20
+
21
+ fontist.org currently consumes (per
22
+ `fontist.org/CLAUDE.md` and `fontist.org/coverage-architecture.md`):
23
+
24
+ - `coverage/{formula_slug}/{PostScriptName}.yaml` — fontisan audit YAML.
25
+ - `woff/{formula_slug}/{PostScriptName}.woff` — WOFF specimens.
26
+ - `fonts.json`, `font-metadata.json` — fonts registry.
27
+ - `unicode/blocks/*.json` — Unicode block reference data.
28
+ - `unicode/indexes/*` — Unicode property indexes.
29
+
30
+ The audit YAML is the fontisan AuditCommand output (legacy). The
31
+ shape is documented in `fontist.org/coverage-architecture.md` §"Audit
32
+ YAML Schema."
33
+
34
+ ## What changes
35
+
36
+ fontist.org gains a parallel data feed for ucode audits:
37
+
38
+ - `audit/{formula_slug}/{PostScriptName}/index.json` — ucode per-face
39
+ AuditReport (TODO 04 contract).
40
+ - `audit/{formula_slug}/{PostScriptName}/blocks/<NAME>.json` — per-block
41
+ chunk.
42
+ - `audit/{formula_slug}/{PostScriptName}/missing/<BLOCK>.html` —
43
+ optional, missing-glyph gallery (TODO 26).
44
+ - `universal_glyph_set/manifest.json` — the universal-set manifest
45
+ (TODO 24), single global file.
46
+ - `universal_glyph_set/glyphs/<U+XXXX>.svg` — universal-set glyphs.
47
+
48
+ The legacy `coverage/` feed stays (fontisan still produces it during
49
+ the migration window). fontist.org's renderer switches to `audit/`
50
+ when present; falls back to `coverage/` when not.
51
+
52
+ ## fontist.org consumer work
53
+
54
+ ### Files to change in `fontist/fontist.org`
55
+
56
+ - `scripts/fetch-data.sh` — add fetch of `audit/` from the archive;
57
+ add fetch of `universal_glyph_set/` (single zip, ~50 MB).
58
+ - `src/lib/fonts/loader.ts` — load the new audit JSON shape; keep
59
+ legacy YAML loader as fallback.
60
+ - `src/lib/unicode/data/loader.ts` — load the universal-set manifest;
61
+ expose `getUniversalGlyph(codepoint)` API.
62
+ - `src/composables/useCoverage.ts` — switch from legacy YAML parsing
63
+ to the new JSON shape; preserve the existing API for component
64
+ compatibility.
65
+ - `src/pages/FontBlockPage.vue` — render missing codepoints using the
66
+ universal-set glyphs (replace the current text-only chips with SVG
67
+ thumbnails when universal set is loaded).
68
+ - `src/pages/FontDetailPage.vue` — use the new `index.json` shape;
69
+ surface tier breakdown ("X glyphs from Tier 1, Y from Pillar 3") in
70
+ the audit footer.
71
+ - `src/components/UnicodeBrowser/` — add a `MissingGlyphGrid.vue`
72
+ component for the drill-down view.
73
+ - `tests/audit-json-shape.test.ts` — independent contract test for
74
+ the new JSON shape (mirrors `spec/fixtures/audit/` in ucode).
75
+
76
+ ### Migration strategy
77
+
78
+ 1. **Phase A — parallel feed.** fontist.org fetches both `coverage/`
79
+ and `audit/`. Renderer uses `audit/` when present (a per-formula
80
+ flag controls rollout). This de-risks the migration.
81
+ 2. **Phase B — audit default.** Once all formulas have audit JSON,
82
+ flip the default. Legacy `coverage/` becomes backup-only.
83
+ 3. **Phase C — coverage decommission.** Stop fetching `coverage/`
84
+ when fontisan audit subsystem is removed (TODO 17-19).
85
+
86
+ ### SSG route additions
87
+
88
+ fontist.org generates static HTML at build time. Per TODO 04, the
89
+ audit is fetched per-font on the client (no per-codepoint static
90
+ HTML). SSG routes:
91
+
92
+ - `/fonts/<slug>/coverage/` — uses `audit/<slug>/<ps>/index.json`
93
+ - `/fonts/<slug>/coverage/<ps>/` — per-face detail
94
+ - `/fonts/<slug>/coverage/<ps>/<block-slug>/` — per-block drill-down
95
+ with missing-glyph grid
96
+
97
+ ~13,200 existing routes grow by ~3,000 audit routes. SSG build time
98
+ budget: under 30 minutes (current: ~25 minutes).
99
+
100
+ ### Universal-set global artifact
101
+
102
+ The universal-set directory is fetched once and shared across all
103
+ font pages. It's served from `/universal-glyph/<U+XXXX>.svg` (no
104
+ formula slug in the URL — it's not per-font).
105
+
106
+ For SSG: don't pre-render every glyph; let the browser fetch on
107
+ demand. The manifest is committed to fontist.org as
108
+ `public/universal-glyph-manifest.json` (~5 MB).
109
+
110
+ ## ucode producer work
111
+
112
+ The producer side is mostly TODO 04 + TODO 13 + TODO 24. What's left:
113
+
114
+ ### Audit JSON emitter gap
115
+
116
+ TODO 13's emitter writes the per-face directory tree. We need a
117
+ top-level emitter that walks a library and produces:
118
+
119
+ ```
120
+ output/font_audit_release/
121
+ ├── audit/<formula_slug>/<ps>/... # one face directory per TODO 03 layout
122
+ ├── universal_glyph_set/... # the universal set (TODO 24)
123
+ ├── library.json # all formulas + faces index
124
+ └── manifest.json # release manifest (versions, sha256s)
125
+ ```
126
+
127
+ This is the artifact `fontist.org/scripts/fetch-data.sh` consumes.
128
+
129
+ ### Files to create in ucode
130
+
131
+ - `lib/ucode/audit/release_emitter.rb` — walks a library audit, emits
132
+ the release tree.
133
+ - `lib/ucode/commands/release.rb` — CLI: `bin/ucode release` produces
134
+ the release tree.
135
+ - `spec/ucode/audit/release_emitter_spec.rb`
136
+
137
+ ### CI / publishing
138
+
139
+ A new GHA workflow in `fontist-archive-private`:
140
+
141
+ 1. Matrix-audit every formula (existing pipeline).
142
+ 2. After all matrix jobs complete, a collector job:
143
+ - Downloads all per-formula audit outputs.
144
+ - Runs `bin/ucode release` to assemble the release tree.
145
+ - Uploads as a GitHub release artifact tagged
146
+ `audit-<unicode-version>-<date>`.
147
+ 3. `fontist.org/scripts/fetch-data.sh` fetches the latest such tag.
148
+
149
+ ## Acceptance
150
+
151
+ ### Producer (ucode)
152
+
153
+ - `bin/ucode release` produces the release tree at
154
+ `output/font_audit_release/`.
155
+ - The release tree contains all per-face audits + the universal-set +
156
+ a library.json + manifest.json.
157
+ - manifest.json records: ucode version, unicode version, source-config
158
+ sha256, per-face count, per-block glyph count from universal set.
159
+ - One smoke spec runs `release` against a small fixture library.
160
+
161
+ ### Consumer (fontist.org)
162
+
163
+ - `scripts/fetch-data.sh` fetches `audit/` and `universal_glyph_set/`
164
+ without errors.
165
+ - A test font page (e.g. `/fonts/manual/inter/coverage/Inter-Regular/`)
166
+ renders using the new JSON shape.
167
+ - The block drill-down view shows missing glyphs as universal-set SVG
168
+ thumbnails.
169
+ - The footer shows tier breakdown ("X glyphs via Tier 1, Y via Pillar
170
+ 3") from the audit baseline.
171
+ - Legacy `coverage/` fallback works when `audit/` is absent.
172
+ - SSG build time stays under 30 minutes.
173
+ - Contract test (`tests/audit-json-shape.test.ts`) passes against the
174
+ fixture from `ucode/spec/fixtures/audit/`.
175
+
176
+ ### Cross-repo
177
+
178
+ - ucode's `spec/fixtures/audit/index.json` matches what fontist.org's
179
+ contract test expects.
180
+ - fontist.org's coverage map renders correctly with both shape
181
+ versions for the migration window.
182
+
183
+ ## Out of scope
184
+
185
+ - The producer-side audit subsystem itself — TODOs 06-16.
186
+ - The universal-set build — TODO 24.
187
+ - fontisan decommission — TODOs 17-19.
188
+ - fontist.org's existing Unicode browser (per-codepoint detail) —
189
+ unchanged; it uses the legacy `unicode/blocks/*.json` data.
190
+
191
+ ## References
192
+
193
+ - fontist.org contract: `TODO.new/04-fontist-org-contract.md`
194
+ - Directory emitter: `TODO.new/13-directory-emitter.md`
195
+ - HTML face browser: `TODO.new/14-html-face-browser.md`
196
+ - Missing glyph reporter: `TODO.new/26-missing-glyph-reporter.md`
197
+ - Universal-set build: `TODO.new/24-universal-glyph-set-build.md`
198
+ - fontist.org consumer repo: `/Users/mulgogi/src/fontist/fontist.org`
199
+ - fontist.org architecture: `fontist.org/CLAUDE.md`
200
+ - Coverage architecture: `fontist.org/coverage-architecture.md`
@@ -0,0 +1,187 @@
1
+ # 28 — Implementation order (universal set + audit + fontist.org)
2
+
3
+ ## Goal
4
+
5
+ Update the canonical implementation order to include TODOs 23-31
6
+ (universal glyph set, font audit against universal set, missing glyph
7
+ reporter, fontist.org consumer integration, full Unicode 17 curation,
8
+ specialist font acquisition, production build + validation). This
9
+ file replaces TODO.new/22 as the authoritative sequencing reference
10
+ for the new work; TODO 22 continues to govern TODOs 01-21.
11
+
12
+ ## Sequencing principles (carried from TODO 22)
13
+
14
+ - **Schema and contract first.** Lock data shapes before porting code.
15
+ - **Measure before optimizing.** Baseline audit (TODO 05) informs the
16
+ source config (TODO 23).
17
+ - **One PR per TODO** unless tightly coupled.
18
+ - **Migration order: port → wire → cleanup.**
19
+
20
+ ## Dependency graph (additions in bold)
21
+
22
+ ```
23
+ 01 pillar-terminology-alignment
24
+ 02 audit-schema-design
25
+ 03 directory-output-spec
26
+ 04 fontist-org-contract
27
+ 05 baseline-unicode17-coverage-audit ───┐
28
+
29
+ 06-16 audit migration track │
30
+
31
+ 17-19 fontisan cleanup │
32
+
33
+ 20 canonical-resolver-4-tier ────────────┤
34
+
35
+ 21 canonical-unicode17-build │
36
+
37
+ **23 universal-glyph-set-source-map** ───┤
38
+
39
+ **24 universal-glyph-set-build** ────────┤
40
+
41
+ **25 font-audit-against-universal-set** ─┤ (shipped — PR #34)
42
+
43
+ **29 universal-set-curation-uc17** ──────┤ (fills TODO 23's YAML)
44
+
45
+ **30 tier1-font-acquisition** ───────────┤ (downloads specialist fonts)
46
+
47
+ **31 universal-set-production-build** ───┤ (executes TODO 24 end-to-end)
48
+
49
+ **26 missing-glyph-reporter** ───────────┤
50
+
51
+ **27 fontist-org-consumer-integration** ─┘
52
+ ```
53
+
54
+ ## Phased rollout
55
+
56
+ ### Phase 1 — Audit migration (TODOs 01-16)
57
+
58
+ Build the audit subsystem in ucode. Mode 2 (per-font audit) lands.
59
+ fontist.org continues consuming legacy `coverage/` YAML during this
60
+ phase.
61
+
62
+ Status (as of this writing): PRs through TODO 12 merged; TODOs 13-16
63
+ in flight.
64
+
65
+ ### Phase 2 — Canonical dataset (TODOs 20-21)
66
+
67
+ Build the resolver (TODO 20) and run the canonical Unicode 17 build
68
+ (TODO 21). Mode 1 (per-codepoint UCD dataset) lands. This work is
69
+ independent of Phase 1; can run in parallel.
70
+
71
+ ### Phase 3 — Universal glyph set (TODOs 23-24) **new**
72
+
73
+ Curate the per-block Tier 1 source map (TODO 23) from the baseline
74
+ audit (TODO 05). Build the universal set as a standalone artifact
75
+ (TODO 24).
76
+
77
+ Dependencies:
78
+ - TODO 05 must be complete (cmap-verified font recommendations).
79
+ - TODO 20 must be merged (resolver mechanics).
80
+ - TODO 21 must have produced a baseline run (validates the resolver).
81
+
82
+ Output: `output/universal_glyph_set/` artifact.
83
+
84
+ ### Phase 4 — Universal-set-driven audit (TODOs 25-26) **new**
85
+
86
+ Replace the cmap-vs-UCD audit (current) with cmap-vs-universal-set
87
+ (TODO 25). Add the missing-glyph drill-down view (TODO 26).
88
+
89
+ Dependencies:
90
+ - TODO 24 must be complete (universal-set manifest exists).
91
+ - TODO 13 must be merged (directory emitter, the wire format).
92
+ - TODO 14 must be merged (face browser, the host of TODO 26 panels).
93
+
94
+ Output: per-font audits carry provenance; missing-glyph galleries
95
+ ship alongside.
96
+
97
+ Status: TODO 25 shipped as PR #34.
98
+
99
+ ### Phase 4b — UC17 curation + production build (TODOs 29-31) **new**
100
+
101
+ Fill the source config with concrete Tier 1 font recommendations for
102
+ all ~340 Unicode 17 blocks (TODO 29). Acquire specialist fonts not in
103
+ fontist's index (TODO 30). Execute the universal-set build end-to-end
104
+ and validate coverage (TODO 31).
105
+
106
+ Dependencies:
107
+ - TODO 23 must be merged (source map mechanism — already shipped).
108
+ - TODO 24 must be merged (build pipeline — already shipped).
109
+ - TODO 05 baseline audit (font investigation analysis, encoded into
110
+ TODO 29).
111
+
112
+ Output: populated `config/unicode17_universal_glyph_set.yml`,
113
+ `data/fonts/<specialist>.ttf`, complete
114
+ `output/universal_glyph_set/` artifact with 100% Tier 1 coverage
115
+ outside documented residual gaps.
116
+
117
+ ### Phase 5 — fontist.org consumer (TODO 27) **new**
118
+
119
+ Wire fontist.org to consume the new audit JSON + universal-set
120
+ glyphs. Parallel-feed alongside legacy `coverage/` during migration.
121
+
122
+ Dependencies:
123
+ - TODO 04 contract locked (already done).
124
+ - TODO 24 universal-set shipped.
125
+ - TODO 25 audit JSON shape stable.
126
+ - TODO 26 missing-glyph galleries available.
127
+ - TODO 31 production build validates (universal-set is complete and
128
+ auditable).
129
+
130
+ Output: fontist.org renders new audit data; legacy feed becomes
131
+ backup-only.
132
+
133
+ ### Phase 6 — fontisan decommission (TODOs 17-19)
134
+
135
+ Once fontist.org has fully migrated to the new feed, remove the
136
+ audit subsystem from fontisan. Out of scope for this doc; tracked in
137
+ TODO 22.
138
+
139
+ ## Cross-cutting concerns
140
+
141
+ ### Source-config stability
142
+
143
+ TODO 23's YAML is the canonical Tier 1 font map. Any change there
144
+ triggers:
145
+ - TODO 24 rebuild (universal-set manifest delta).
146
+ - TODO 25 re-audit (per-block coverage may shift).
147
+ - TODO 27 re-release (fontist.org fetches new manifest).
148
+
149
+ Recommendation: bump `ucode_version` field on every config edit;
150
+ consumers detect drift via that field.
151
+
152
+ ### Performance
153
+
154
+ - TODO 24 build: target under 4 hours for full Unicode 17.
155
+ - TODO 25 re-audit: per-font is independent; can parallelize across CI
156
+ matrix (one job per formula).
157
+ - TODO 27 SSG build: target under 30 minutes (current ~25).
158
+
159
+ ### Backwards compatibility
160
+
161
+ - TODO 25 audit JSON: additive field (`missing_codepoint_provenance`).
162
+ Old consumers ignore the new field.
163
+ - TODO 27 consumer: parallel-feed during migration; legacy fallback
164
+ when audit JSON is absent.
165
+
166
+ ## Acceptance
167
+
168
+ - All Phase 3-5 TODOs ship as one PR each.
169
+ - The sequencing above is reflected in the actual PR stack on GitHub.
170
+ - TODO 22 is updated to cross-reference this file.
171
+
172
+ ## Out of scope
173
+
174
+ - Anything already covered by TODO 22 (TODOs 01-21).
175
+ - fontisan decommission (Phase 6, TODO 22).
176
+
177
+ ## References
178
+
179
+ - Predecessor: `TODO.new/22-implementation-order.md`
180
+ - Universal-set source map: `TODO.new/23-universal-glyph-set-source-map.md`
181
+ - Universal-set build: `TODO.new/24-universal-glyph-set-build.md`
182
+ - Font audit against universal set: `TODO.new/25-font-audit-against-universal-set.md`
183
+ - Missing glyph reporter: `TODO.new/26-missing-glyph-reporter.md`
184
+ - fontist.org consumer integration: `TODO.new/27-fontist-org-consumer-integration.md`
185
+ - UC17 curation (Part 1): `TODO.new/29-universal-set-curation-uc17.md`
186
+ - Tier 1 font acquisition: `TODO.new/30-tier1-font-acquisition.md`
187
+ - Production build + validation: `TODO.new/31-universal-set-production-build.md`