ucode 0.3.3 → 0.4.0
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.
- checksums.yaml +4 -4
- data/config/unicode17_universal_glyph_set.yml +1 -1
- data/lib/ucode/code_chart/extractor.rb +7 -3
- data/lib/ucode/code_chart/writer.rb +1 -1
- data/lib/ucode/error.rb +5 -0
- data/lib/ucode/glyphs/embedded_fonts/catalog.rb +20 -3
- data/lib/ucode/glyphs/embedded_fonts/codepoint_mapper/correlator_strategy.rb +46 -0
- data/lib/ucode/glyphs/embedded_fonts/codepoint_mapper/strategy.rb +54 -0
- data/lib/ucode/glyphs/embedded_fonts/codepoint_mapper/tounicode_strategy.rb +41 -0
- data/lib/ucode/glyphs/embedded_fonts/codepoint_mapper/trace_strategy.rb +64 -0
- data/lib/ucode/glyphs/embedded_fonts/codepoint_mapper.rb +143 -90
- data/lib/ucode/glyphs/embedded_fonts/mutool/draw.rb +26 -0
- data/lib/ucode/glyphs/embedded_fonts/mutool/info.rb +23 -0
- data/lib/ucode/glyphs/embedded_fonts/mutool/show.rb +36 -0
- data/lib/ucode/glyphs/embedded_fonts/mutool/trace.rb +26 -0
- data/lib/ucode/glyphs/embedded_fonts/mutool.rb +30 -0
- data/lib/ucode/glyphs/embedded_fonts/page_trace_cache.rb +90 -0
- data/lib/ucode/glyphs/embedded_fonts/pdf_indexer.rb +50 -56
- data/lib/ucode/glyphs/embedded_fonts/{pdf_location.rb → pdf_source.rb} +1 -1
- data/lib/ucode/glyphs/embedded_fonts/trace_runner.rb +12 -28
- data/lib/ucode/glyphs/embedded_fonts.rb +3 -1
- data/lib/ucode/glyphs/real_fonts/coverage_auditor.rb +0 -4
- data/lib/ucode/glyphs/real_fonts/font_coverage_report.rb +0 -2
- data/lib/ucode/glyphs/real_fonts/writer.rb +0 -2
- data/lib/ucode/glyphs/sources/pillar1_embedded_tounicode.rb +1 -1
- data/lib/ucode/version.rb +1 -1
- metadata +13 -74
- data/TODO.extract-code-chart/01-pdf-fetch-validation.md +0 -80
- data/TODO.extract-code-chart/02-block-name-resolver.md +0 -68
- data/TODO.extract-code-chart/03-codechart-namespace.md +0 -82
- data/TODO.extract-code-chart/04-codechart-extractor.md +0 -154
- data/TODO.extract-code-chart/05-provenance-and-sidecar.md +0 -147
- data/TODO.extract-code-chart/06-codechart-writer.md +0 -134
- data/TODO.extract-code-chart/07-codechart-cli.md +0 -135
- data/TODO.extract-code-chart/08-specs.md +0 -87
- data/TODO.full/00-README.md +0 -116
- data/TODO.full/01-panglyph-vision.md +0 -112
- data/TODO.full/02-panglyph-repo-bootstrap.md +0 -184
- data/TODO.full/03-panglyph-font-builder.md +0 -201
- data/TODO.full/04-panglyph-publish-pipeline.md +0 -126
- data/TODO.full/05-ucode-0-1-1-release.md +0 -139
- data/TODO.full/06-fontisan-remove-audit.md +0 -142
- data/TODO.full/07-fontisan-remove-ucd.md +0 -125
- data/TODO.full/08-archive-private-bin-build.md +0 -143
- data/TODO.full/09-archive-public-structure.md +0 -164
- data/TODO.full/10-fontist-org-woff-glyphs.md +0 -131
- data/TODO.full/11-fontist-org-audit-coverage.md +0 -140
- data/TODO.full/12-implementation-order.md +0 -216
- data/TODO.full/13-fontisan-font-writer-api.md +0 -189
- data/TODO.full/14-fontisan-table-writers.md +0 -66
- data/TODO.full/15-panglyph-builder-real.md +0 -82
- data/TODO.full/16-archive-public-sync-workflows.md +0 -167
- data/TODO.full/17-fontist-org-font-picker.md +0 -73
- data/TODO.full/18-comprehensive-spec-coverage.md +0 -64
- data/TODO.full/19-ucode-0-1-2-patch.md +0 -32
- data/TODO.full/20-fontisan-0-2-23-release.md +0 -52
- data/TODO.new/00-README.md +0 -96
- data/TODO.new/01-pillar-terminology-alignment.md +0 -69
- data/TODO.new/02-audit-schema-design.md +0 -255
- data/TODO.new/03-directory-output-spec.md +0 -203
- data/TODO.new/04-fontist-org-contract.md +0 -173
- data/TODO.new/05-baseline-unicode17-coverage-audit.md +0 -144
- data/TODO.new/06-audit-namespace-skeleton.md +0 -105
- data/TODO.new/07-audit-models-port.md +0 -132
- data/TODO.new/08-extractors-cheap-port.md +0 -113
- data/TODO.new/09-extractors-expensive-port.md +0 -99
- data/TODO.new/10-aggregations-ucd-rewrite.md +0 -168
- data/TODO.new/11-differ-and-library-auditor-port.md +0 -102
- data/TODO.new/12-formatters-port.md +0 -115
- data/TODO.new/13-directory-emitter.md +0 -147
- data/TODO.new/14-html-face-browser.md +0 -144
- data/TODO.new/15-html-library-browser.md +0 -102
- data/TODO.new/16-cli-audit-subcommands.md +0 -142
- data/TODO.new/17-fontisan-cleanup-audit.md +0 -147
- data/TODO.new/18-fontisan-cleanup-ucd.md +0 -156
- data/TODO.new/19-fontisan-docs-update.md +0 -155
- data/TODO.new/20-canonical-resolver-4-tier.md +0 -182
- data/TODO.new/21-canonical-unicode17-build.md +0 -148
- data/TODO.new/22-implementation-order.md +0 -176
- data/TODO.new/23-universal-glyph-set-source-map.md +0 -312
- data/TODO.new/24-universal-glyph-set-build.md +0 -189
- data/TODO.new/25-font-audit-against-universal-set.md +0 -195
- data/TODO.new/26-missing-glyph-reporter.md +0 -189
- data/TODO.new/27-fontist-org-consumer-integration.md +0 -200
- data/TODO.new/28-implementation-order-update.md +0 -187
- data/TODO.new/29-universal-set-curation-uc17.md +0 -312
- data/TODO.new/30-tier1-font-acquisition.md +0 -241
- data/TODO.new/31-universal-set-production-build.md +0 -205
- data/TODO.new/32-uc17-coverage-matrix.md +0 -165
- data/TODO.new/33-specialist-font-acquisition-refresh.md +0 -138
- data/TODO.new/34-pillar2-content-stream-correlator.md +0 -147
- data/TODO.new/35-universal-set-production-run.md +0 -160
- data/TODO.new/36-per-font-coverage-audit.md +0 -145
- data/TODO.new/37-coverage-highlight-reporter.md +0 -125
- data/TODO.new/38-fontist-org-glyph-consumer.md +0 -141
- data/TODO.new/39-implementation-order-update-32-38.md +0 -258
- data/TODO.new/40-archive-private-uses-ucode-audit.md +0 -124
- data/TODO.new/41-ucode-unicode-archive-bridge.md +0 -160
|
@@ -1,167 +0,0 @@
|
|
|
1
|
-
# 16 — archive-public: three sync workflows (GHA)
|
|
2
|
-
|
|
3
|
-
## Goal
|
|
4
|
-
|
|
5
|
-
Add the three GitHub Actions workflows that sync `fontist-archive-public`
|
|
6
|
-
from its three upstream sources:
|
|
7
|
-
|
|
8
|
-
1. `sync-private.yml` — pulls from `fontist-archive-private` on push
|
|
9
|
-
2. `sync-ucode.yml` — pulls from `fontist/ucode` publish workflow
|
|
10
|
-
3. `sync-panglyph.yml` — pulls from `fontist/panglyph` tag pushes
|
|
11
|
-
|
|
12
|
-
Each writes to a disjoint directory (`coverage/`, `unicode/`, `panglyph/`),
|
|
13
|
-
so concurrent runs don't conflict.
|
|
14
|
-
|
|
15
|
-
## Why this is a separate TODO
|
|
16
|
-
|
|
17
|
-
The directory placeholders exist (committed in the
|
|
18
|
-
`audit/add-unicode-and-panglyph-dirs` branch). The sync workflows are
|
|
19
|
-
the actual machinery. Without them, the directories stay empty.
|
|
20
|
-
|
|
21
|
-
## Scope
|
|
22
|
-
|
|
23
|
-
### sync-private.yml
|
|
24
|
-
|
|
25
|
-
```yaml
|
|
26
|
-
name: Sync from fontist-archive-private
|
|
27
|
-
|
|
28
|
-
on:
|
|
29
|
-
repository_dispatch:
|
|
30
|
-
types: [archive-private-updated]
|
|
31
|
-
workflow_dispatch:
|
|
32
|
-
|
|
33
|
-
jobs:
|
|
34
|
-
sync:
|
|
35
|
-
runs-on: ubuntu-latest
|
|
36
|
-
steps:
|
|
37
|
-
- uses: actions/checkout@v4
|
|
38
|
-
- name: Clone private (read-only deploy key)
|
|
39
|
-
env:
|
|
40
|
-
SSH_KEY: ${{ secrets.ARCHIVE_PRIVATE_DEPLOY_KEY }}
|
|
41
|
-
run: |
|
|
42
|
-
mkdir -p ~/.ssh && echo "$SSH_KEY" > ~/.ssh/id_ed25519 && chmod 600 ~/.ssh/id_ed25519
|
|
43
|
-
git clone --depth 1 git@github.com:fontist/fontist-archive-private.git /tmp/private
|
|
44
|
-
- name: Sync coverage/
|
|
45
|
-
run: |
|
|
46
|
-
rm -rf coverage
|
|
47
|
-
cp -r /tmp/private/coverage .
|
|
48
|
-
- name: Sync woff/ (open-license only)
|
|
49
|
-
run: |
|
|
50
|
-
rm -rf woff
|
|
51
|
-
mkdir -p woff
|
|
52
|
-
for d in /tmp/private/woff/*; do
|
|
53
|
-
base=$(basename "$d")
|
|
54
|
-
[ "$base" != "macos" ] && cp -r "$d" "woff/"
|
|
55
|
-
done
|
|
56
|
-
- name: Sync fonts.json + font-metadata.json
|
|
57
|
-
run: cp /tmp/private/fonts.json /tmp/private/font-metadata.json . || true
|
|
58
|
-
- name: Commit
|
|
59
|
-
run: |
|
|
60
|
-
git config user.email "archive-bot@fontist.org"
|
|
61
|
-
git config user.name "archive-bot"
|
|
62
|
-
git add -A
|
|
63
|
-
git diff --quiet HEAD || git commit -m "Sync from fontist-archive-private @ $(date -u +%Y-%m-%dT%H:%M:%SZ)"
|
|
64
|
-
git push
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
### sync-ucode.yml
|
|
68
|
-
|
|
69
|
-
```yaml
|
|
70
|
-
name: Sync from fontist/ucode
|
|
71
|
-
|
|
72
|
-
on:
|
|
73
|
-
workflow_run:
|
|
74
|
-
workflows: [publish-unicode-archive]
|
|
75
|
-
types: [completed]
|
|
76
|
-
branches: [main]
|
|
77
|
-
workflow_dispatch:
|
|
78
|
-
|
|
79
|
-
jobs:
|
|
80
|
-
sync:
|
|
81
|
-
runs-on: ubuntu-latest
|
|
82
|
-
if: github.event.workflow_run.conclusion == 'success'
|
|
83
|
-
steps:
|
|
84
|
-
- uses: actions/checkout@v4
|
|
85
|
-
- name: Download ucode artifacts
|
|
86
|
-
uses: actions/github-script@v7
|
|
87
|
-
with:
|
|
88
|
-
script: |
|
|
89
|
-
const runId = context.payload.workflow_run.id
|
|
90
|
-
const artifacts = await github.rest.actions.listWorkflowRunArtifacts({
|
|
91
|
-
owner: 'fontist', repo: 'ucode', run_id: runId
|
|
92
|
-
})
|
|
93
|
-
// download unicode-block-feed.tar.gz + universal-glyph-set.tar.gz
|
|
94
|
-
// ...
|
|
95
|
-
- name: Sync unicode/
|
|
96
|
-
run: |
|
|
97
|
-
rm -rf unicode/block-feed unicode/universal-glyph-set
|
|
98
|
-
mkdir -p unicode/block-feed unicode/universal-glyph-set
|
|
99
|
-
tar xzf /tmp/block-feed.tar.gz -C unicode/block-feed
|
|
100
|
-
tar xzf /tmp/universal-glyph-set.tar.gz -C unicode/universal-glyph-set
|
|
101
|
-
- name: Commit
|
|
102
|
-
run: |
|
|
103
|
-
git config user.email "archive-bot@fontist.org"
|
|
104
|
-
git config user.name "archive-bot"
|
|
105
|
-
git add -A unicode/
|
|
106
|
-
git diff --quiet HEAD -- unicode/ || git commit -m "Sync unicode/ from fontist/ucode"
|
|
107
|
-
git push
|
|
108
|
-
```
|
|
109
|
-
|
|
110
|
-
### sync-panglyph.yml
|
|
111
|
-
|
|
112
|
-
```yaml
|
|
113
|
-
name: Sync from fontist/panglyph
|
|
114
|
-
|
|
115
|
-
on:
|
|
116
|
-
repository_dispatch:
|
|
117
|
-
types: [panglyph-released]
|
|
118
|
-
workflow_dispatch:
|
|
119
|
-
inputs:
|
|
120
|
-
version:
|
|
121
|
-
description: 'panglyph version (e.g. 17.0.0)'
|
|
122
|
-
required: true
|
|
123
|
-
|
|
124
|
-
jobs:
|
|
125
|
-
sync:
|
|
126
|
-
runs-on: ubuntu-latest
|
|
127
|
-
steps:
|
|
128
|
-
- uses: actions/checkout@v4
|
|
129
|
-
- name: Download panglyph release
|
|
130
|
-
env:
|
|
131
|
-
GH_TOKEN: ${{ secrets.ARCHIVE_PUBLIC_BOT_TOKEN }}
|
|
132
|
-
run: |
|
|
133
|
-
VERSION="${{ inputs.version || github.event.client_payload.version }}"
|
|
134
|
-
gh release download "v${VERSION}" \
|
|
135
|
-
--repo fontist/panglyph \
|
|
136
|
-
--pattern "panglyph-unicode*.{ttf,woff2,otf}" \
|
|
137
|
-
--pattern "coverage-report.json" \
|
|
138
|
-
--pattern "source-manifest.json" \
|
|
139
|
-
--dir "/tmp/v${VERSION}"
|
|
140
|
-
- name: Sync panglyph/
|
|
141
|
-
run: |
|
|
142
|
-
mkdir -p "panglyph/v${VERSION}"
|
|
143
|
-
cp /tmp/v${VERSION}/* "panglyph/v${VERSION}/"
|
|
144
|
-
# Update top-level manifest.json (script in bin/update-panglyph-manifest.rb)
|
|
145
|
-
ruby bin/update-panglyph-manifest.rb "${VERSION}"
|
|
146
|
-
- name: Commit
|
|
147
|
-
run: |
|
|
148
|
-
git config user.email "archive-bot@fontist.org"
|
|
149
|
-
git config user.name "archive-bot"
|
|
150
|
-
git add -A panglyph/
|
|
151
|
-
git diff --quiet HEAD -- panglyph/ || git commit -m "Sync panglyph v${VERSION}"
|
|
152
|
-
git push
|
|
153
|
-
```
|
|
154
|
-
|
|
155
|
-
## Acceptance
|
|
156
|
-
|
|
157
|
-
- [ ] All three workflows exist + are syntactically valid YAML
|
|
158
|
-
- [ ] Each writes to a disjoint directory
|
|
159
|
-
- [ ] Manual dispatch works (`workflow_dispatch`)
|
|
160
|
-
- [ ] Trigger-based dispatch works (`repository_dispatch` / `workflow_run`)
|
|
161
|
-
- [ ] Bot commits identify as `archive-bot@fontist.org`
|
|
162
|
-
|
|
163
|
-
## References
|
|
164
|
-
|
|
165
|
-
- [TODO.full/09](09-archive-public-structure.md) — target structure
|
|
166
|
-
- [TODO.full/04](04-panglyph-publish-pipeline.md) — panglyph publish trigger
|
|
167
|
-
- [TODO.new/41](../TODO.new/41-ucode-unicode-archive-bridge.md) — ucode publish trigger
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
# 17 — fontist.org: font picker on the universal Unicode browser
|
|
2
|
-
|
|
3
|
-
## Goal
|
|
4
|
-
|
|
5
|
-
Add a font picker to the standalone `/unicode` page so users can browse
|
|
6
|
-
Unicode with a specific font active. Today the universal browser uses
|
|
7
|
-
system fallback fonts; selecting a font from `public/fonts/*.woff2`
|
|
8
|
-
injects `@font-face` and renders every glyph in that font.
|
|
9
|
-
|
|
10
|
-
Pairs with the existing `/fonts/{slug}/unicode` page (FontUnicodePage),
|
|
11
|
-
which already does this — but only for one font at a time. The universal
|
|
12
|
-
browser should let users switch fonts without leaving `/unicode`.
|
|
13
|
-
|
|
14
|
-
## Why this is a separate TODO
|
|
15
|
-
|
|
16
|
-
TODO.full/10 covered the rendering primitives (useFontFace composable,
|
|
17
|
-
FontPicker component, etc.). The integration work — wiring the picker
|
|
18
|
-
into `/unicode`, persisting selection, surfacing on the block + char
|
|
19
|
-
pages — is separate.
|
|
20
|
-
|
|
21
|
-
## Scope
|
|
22
|
-
|
|
23
|
-
### Phase A — Reuse the existing FontPicker
|
|
24
|
-
|
|
25
|
-
1. The `FontStyleUnicodePage` already injects `@font-face` via
|
|
26
|
-
`injectFontFace(slug, 'fonts/${slug}.woff2', true)`. Extract this
|
|
27
|
-
into a global composable that any page can call.
|
|
28
|
-
|
|
29
|
-
2. Add a `<FontPicker>` component to `/unicode` (top of page, sticky).
|
|
30
|
-
|
|
31
|
-
3. On font selection: set a global Pinia store (or provide/inject)
|
|
32
|
-
so all child routes inherit the active font.
|
|
33
|
-
|
|
34
|
-
### Phase B — Coverage overlay
|
|
35
|
-
|
|
36
|
-
4. When a font is active on `/unicode`:
|
|
37
|
-
- Each block row shows: `[coverage bar: 128/128 = 100%]` next to the name
|
|
38
|
-
- Color-coded: green ≥95%, yellow 50-95%, red <50%
|
|
39
|
-
- Click → navigates to `/unicode/block/<slug>?font=<active-slug>`
|
|
40
|
-
|
|
41
|
-
5. On `/unicode/block/<slug>`:
|
|
42
|
-
- If `?font=X` is set, inject X's WOFF + show coverage overlay on each cell
|
|
43
|
-
- Cells with chars the font covers: render in WOFF
|
|
44
|
-
- Cells with chars the font misses: gray out + tooltip "Not in X"
|
|
45
|
-
|
|
46
|
-
### Phase C — Persistence
|
|
47
|
-
|
|
48
|
-
6. Active font persists across page navigation via `localStorage`.
|
|
49
|
-
|
|
50
|
-
7. URL parameter `?font=X` overrides localStorage. Useful for sharing
|
|
51
|
-
links like "view this block in Noto Sans".
|
|
52
|
-
|
|
53
|
-
### Phase D — "Best font per block" page
|
|
54
|
-
|
|
55
|
-
8. New route `/unicode/best-fonts/{block-slug}`: lists fonts sorted by
|
|
56
|
-
fill ratio for that block. Top result is the canonical Tier 1 font
|
|
57
|
-
from ucode's universal-set manifest.
|
|
58
|
-
|
|
59
|
-
## Acceptance
|
|
60
|
-
|
|
61
|
-
- [ ] `/unicode` shows FontPicker at top
|
|
62
|
-
- [ ] Selecting a font injects `@font-face` and re-renders the page
|
|
63
|
-
- [ ] Block list shows coverage bars when a font is active
|
|
64
|
-
- [ ] Block detail page respects `?font=X`
|
|
65
|
-
- [ ] Active font persists in localStorage
|
|
66
|
-
- [ ] `/unicode/best-fonts/{block}` exists
|
|
67
|
-
|
|
68
|
-
## References
|
|
69
|
-
|
|
70
|
-
- [TODO.full/10](10-fontist-org-woff-glyphs.md) — rendering primitives
|
|
71
|
-
- [TODO.full/11](11-fontist-org-audit-coverage.md) — coverage data layer
|
|
72
|
-
- `src/pages/FontUnicodePage.vue` — existing per-font page (pattern source)
|
|
73
|
-
- `src/composables/useFontFace.ts` — existing composable
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
# 18 — Comprehensive spec coverage for new code
|
|
2
|
-
|
|
3
|
-
## Goal
|
|
4
|
-
|
|
5
|
-
Every class added in TODO.full/13–17 must have specs covering:
|
|
6
|
-
- Public API behavior
|
|
7
|
-
- Edge cases (empty input, malformed input, boundary values)
|
|
8
|
-
- Round-trip serialization (write → read = same data)
|
|
9
|
-
- Performance (no obvious pathological cases for 299k codepoints)
|
|
10
|
-
|
|
11
|
-
## Why a separate TODO
|
|
12
|
-
|
|
13
|
-
Quality bar per global rules: "Good specs throughout. Every public
|
|
14
|
-
method should have specs. Every behavioral edge case should be covered.
|
|
15
|
-
Specs use real model instances — never doubles."
|
|
16
|
-
|
|
17
|
-
The new code (FontWriter, panglyph Builder, font picker integration)
|
|
18
|
-
touches core paths. Without specs, regressions slip silently.
|
|
19
|
-
|
|
20
|
-
## Scope
|
|
21
|
-
|
|
22
|
-
### fontisan FontWriter (TODO.full/13, 14)
|
|
23
|
-
|
|
24
|
-
- `FontWriter#set_cmap` — empty, single entry, full BMP, supplementary
|
|
25
|
-
- `FontWriter#add_glyph` — simple outline, composite outline, no instructions
|
|
26
|
-
- `FontWriter#set_name_records` — all 6 standard name_ids
|
|
27
|
-
- `FontWriter#write_to` — round-trip: write → reopen via Fontisan::Font.open
|
|
28
|
-
- Per-table specs:
|
|
29
|
-
- `Tables::Head` — byte-exact comparison with a known fixture
|
|
30
|
-
- `Tables::Cmap` — format 4 BMP, format 12 supplementary, both
|
|
31
|
-
- `Tables::Glyf` — simple glyph, composite glyph, empty glyph (.notdef)
|
|
32
|
-
- etc.
|
|
33
|
-
|
|
34
|
-
### panglyph (TODO.full/15)
|
|
35
|
-
|
|
36
|
-
- `Builder#call` — full pipeline with a 5-codepoint fixture
|
|
37
|
-
- `OutlineExtractor#extract_many` — real font, 3 codepoints
|
|
38
|
-
- `FontAssembler#assemble` — output TTF opens via Fontisan::Font.open
|
|
39
|
-
- `CoverageReport#validate_font` — known gap → reported in missing_codepoints
|
|
40
|
-
- `Publisher#call` — atomic sync to temp git repo fixture
|
|
41
|
-
|
|
42
|
-
### fontist.org (TODO.full/17)
|
|
43
|
-
|
|
44
|
-
- `FontPicker.vue` — emits selection event
|
|
45
|
-
- `useActiveFont` composable — persists to localStorage
|
|
46
|
-
- `/unicode/best-fonts/{block}` — sorts by fill_ratio desc
|
|
47
|
-
|
|
48
|
-
### Integration specs
|
|
49
|
-
|
|
50
|
-
- End-to-end: ucode parse → universal-set build → panglyph build → archive sync → fontist.org fetch
|
|
51
|
-
- Smoke test: built panglyph TTF renders U+0041 in a headless browser
|
|
52
|
-
|
|
53
|
-
## Acceptance
|
|
54
|
-
|
|
55
|
-
- [ ] Every new public class has a corresponding spec file
|
|
56
|
-
- [ ] Every public method has at least one happy-path + one edge-case spec
|
|
57
|
-
- [ ] Round-trip specs exist for any serialization path
|
|
58
|
-
- [ ] `bundle exec rspec` passes on all repos
|
|
59
|
-
- [ ] No `double()` usage (per global rule)
|
|
60
|
-
|
|
61
|
-
## References
|
|
62
|
-
|
|
63
|
-
- Global rule: "Good specs throughout"
|
|
64
|
-
- `spec/support/model_round_trip.rb` — shared example for round-trip models
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
# 19 — ucode 0.1.2 patch: include FontWriter + universal-set fixes
|
|
2
|
-
|
|
3
|
-
## Goal
|
|
4
|
-
|
|
5
|
-
After TODO.full/13 (FontWriter) lands in fontisan, bump ucode to 0.1.2
|
|
6
|
-
with whatever fixes accumulated. Keep the gem install path stable for
|
|
7
|
-
fontist-archive-private CI.
|
|
8
|
-
|
|
9
|
-
## Why a separate TODO
|
|
10
|
-
|
|
11
|
-
ucode 0.1.1 (TODO.full/05) ships the audit subsystem + BlockFeedEmitter.
|
|
12
|
-
0.1.2 is a routine patch — no SemVer drama, just iteration. Bundles
|
|
13
|
-
whatever real-data fixes surface when CI actually runs against all
|
|
14
|
-
formulas.
|
|
15
|
-
|
|
16
|
-
## Scope
|
|
17
|
-
|
|
18
|
-
- Bump `lib/ucode/version.rb` to `0.1.2`
|
|
19
|
-
- Add CHANGELOG entry (typically: 1-2 fixes)
|
|
20
|
-
- Run full test suite + rubocop
|
|
21
|
-
- Open PR + tag + release per standard release process
|
|
22
|
-
|
|
23
|
-
## Acceptance
|
|
24
|
-
|
|
25
|
-
- [ ] Version bumped
|
|
26
|
-
- [ ] CHANGELOG documents 0.1.2
|
|
27
|
-
- [ ] Specs green
|
|
28
|
-
- [ ] Tag v0.1.2 + `rake release` (with explicit user authorization)
|
|
29
|
-
|
|
30
|
-
## References
|
|
31
|
-
|
|
32
|
-
- [TODO.full/05](05-ucode-0-1-1-release.md) — prior release process
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
# 20 — fontisan 0.2.23: ship FontWriter
|
|
2
|
-
|
|
3
|
-
## Goal
|
|
4
|
-
|
|
5
|
-
Once TODO.full/13 (FontWriter API) + TODO.full/14 (table writers) are
|
|
6
|
-
merged to main, ship fontisan 0.2.23 with the new capability. Stays
|
|
7
|
-
on 0.2.x because the removal of audit + UCD was framed as dead-code
|
|
8
|
-
cleanup, not a SemVer event.
|
|
9
|
-
|
|
10
|
-
## Why this is a separate TODO
|
|
11
|
-
|
|
12
|
-
panglyph's gemspec depends on `fontisan, "~> 0.3"` today (the bootstrap
|
|
13
|
-
commit assumed the 0.3.0 bump). After your correction (no bump), the
|
|
14
|
-
constraint needs to relax to `~> 0.2` to pick up FontWriter in 0.2.23.
|
|
15
|
-
|
|
16
|
-
## Scope
|
|
17
|
-
|
|
18
|
-
1. Verify TODO.full/13 + 14 are merged to main.
|
|
19
|
-
2. Bump `lib/fontisan/version.rb` to `0.2.23`.
|
|
20
|
-
3. Add CHANGELOG entry:
|
|
21
|
-
```markdown
|
|
22
|
-
## [0.2.23] — 2026-XX-XX
|
|
23
|
-
|
|
24
|
-
### Added
|
|
25
|
-
|
|
26
|
-
- `Fontisan::FontWriter` — new API for assembling fonts from scratch
|
|
27
|
-
(cmap + glyf + name + metrics). Pairs with the existing font-reading
|
|
28
|
-
API. Enables downstream consumers (panglyph) to build new fonts
|
|
29
|
-
from extracted outlines.
|
|
30
|
-
- `Fontisan::FontWriter::Tables::*` — one writer class per OpenType
|
|
31
|
-
table (Head, Cmap, Hmtx, Hhea, Glyf, Loca, Maxp, Os2, Post, Name).
|
|
32
|
-
- Typed structs: `Outline`, `Point`, `NameRecord`, `Metrics`,
|
|
33
|
-
`GlyphEntry`, `FontModel`.
|
|
34
|
-
```
|
|
35
|
-
4. Update panglyph gemspec: `gem "fontisan", "~> 0.2"` (was `~> 0.3`).
|
|
36
|
-
5. Run full test suite + rubocop.
|
|
37
|
-
6. Open PR + tag + release.
|
|
38
|
-
|
|
39
|
-
## Acceptance
|
|
40
|
-
|
|
41
|
-
- [ ] Version bumped to 0.2.23
|
|
42
|
-
- [ ] CHANGELOG entry documents FontWriter addition
|
|
43
|
-
- [ ] panglyph.gemspec constraint relaxed to `~> 0.2`
|
|
44
|
-
- [ ] `bundle exec panglyph version` works against the new fontisan
|
|
45
|
-
- [ ] Tag v0.2.23 + `rake release` (with explicit user authorization)
|
|
46
|
-
|
|
47
|
-
## References
|
|
48
|
-
|
|
49
|
-
- [TODO.full/06](06-fontisan-remove-audit.md) — why we stayed on 0.2.x
|
|
50
|
-
- [TODO.full/07](07-fontisan-remove-ucd.md) — same reasoning
|
|
51
|
-
- [TODO.full/13](13-fontisan-font-writer-api.md) — what 0.2.23 ships
|
|
52
|
-
- [TODO.full/14](14-fontisan-table-writers.md) — companion
|
data/TODO.new/00-README.md
DELETED
|
@@ -1,96 +0,0 @@
|
|
|
1
|
-
# TODO.new — audit migration + Mode 2 work
|
|
2
|
-
|
|
3
|
-
Work tracks for the fontisan audit → ucode audit migration, the
|
|
4
|
-
per-font-audit output spec, and the Mode 1 canonical-dataset alignment.
|
|
5
|
-
The full architecture reference is `docs/architecture.md` — read that
|
|
6
|
-
first; these TODOs reference sections of it.
|
|
7
|
-
|
|
8
|
-
## Tracks
|
|
9
|
-
|
|
10
|
-
### Alignment & contract (lock these before any code moves)
|
|
11
|
-
|
|
12
|
-
- [01 — Pillar terminology alignment](01-pillar-terminology-alignment.md)
|
|
13
|
-
- [02 — Audit schema design](02-audit-schema-design.md)
|
|
14
|
-
- [03 — Directory output spec](03-directory-output-spec.md)
|
|
15
|
-
- [04 — fontist.org contract](04-fontist-org-contract.md)
|
|
16
|
-
|
|
17
|
-
### Baseline measurement (know where we are)
|
|
18
|
-
|
|
19
|
-
- [05 — Unicode 17 baseline coverage audit](05-baseline-unicode17-coverage-audit.md)
|
|
20
|
-
|
|
21
|
-
### Audit migration (the big work)
|
|
22
|
-
|
|
23
|
-
- [06 — Audit namespace skeleton](06-audit-namespace-skeleton.md)
|
|
24
|
-
- [07 — Models::Audit port](07-audit-models-port.md)
|
|
25
|
-
- [08 — Cheap extractors port](08-extractors-cheap-port.md)
|
|
26
|
-
- [09 — Expensive extractors port](09-extractors-expensive-port.md)
|
|
27
|
-
- [10 — Aggregations rewrite on ucode UCD](10-aggregations-ucd-rewrite.md)
|
|
28
|
-
- [11 — Differ + library auditor port](11-differ-and-library-auditor-port.md)
|
|
29
|
-
- [12 — Formatters port](12-formatters-port.md)
|
|
30
|
-
|
|
31
|
-
### Output + browser
|
|
32
|
-
|
|
33
|
-
- [13 — Directory emitter](13-directory-emitter.md)
|
|
34
|
-
- [14 — HTML face browser](14-html-face-browser.md)
|
|
35
|
-
- [15 — HTML library browser](15-html-library-browser.md)
|
|
36
|
-
- [16 — CLI audit subcommands](16-cli-audit-subcommands.md)
|
|
37
|
-
|
|
38
|
-
### Fontisan cleanup (after ucode audit ships)
|
|
39
|
-
|
|
40
|
-
- [17 — Fontisan: delete audit subsystem](17-fontisan-cleanup-audit.md)
|
|
41
|
-
- [18 — Fontisan: delete UCD subsystem](18-fontisan-cleanup-ucd.md)
|
|
42
|
-
- [19 — Fontisan: docs and shim update](19-fontisan-docs-update.md)
|
|
43
|
-
|
|
44
|
-
### Canonical Mode 1 alignment
|
|
45
|
-
|
|
46
|
-
- [20 — Canonical 4-tier resolver](20-canonical-resolver-4-tier.md)
|
|
47
|
-
- [21 — Canonical Unicode 17 dataset build](21-canonical-unicode17-build.md)
|
|
48
|
-
|
|
49
|
-
### Universal glyph set + UC17 curation
|
|
50
|
-
|
|
51
|
-
- [23 — Universal glyph set: Tier 1 source map](23-universal-glyph-set-source-map.md)
|
|
52
|
-
- [24 — Universal glyph set build](24-universal-glyph-set-build.md)
|
|
53
|
-
- [25 — Font audit against universal set](25-font-audit-against-universal-set.md)
|
|
54
|
-
- [26 — Missing glyph reporter (drill-down view)](26-missing-glyph-reporter.md)
|
|
55
|
-
- [27 — fontist.org consumer integration](27-fontist-org-consumer-integration.md)
|
|
56
|
-
- [29 — Universal glyph set: full Unicode 17 curation (Part 1)](29-universal-set-curation-uc17.md)
|
|
57
|
-
- [30 — Tier 1 font acquisition: specialist fonts](30-tier1-font-acquisition.md)
|
|
58
|
-
- [31 — Universal set production build + coverage validation](31-universal-set-production-build.md)
|
|
59
|
-
|
|
60
|
-
### Full UC17 coverage + per-font audit (Part 1 close + Part 2)
|
|
61
|
-
|
|
62
|
-
- [32 — Universal glyph set: full UC17 coverage matrix (Part 1 master)](32-uc17-coverage-matrix.md)
|
|
63
|
-
- [33 — Specialist font acquisition refresh](33-specialist-font-acquisition-refresh.md)
|
|
64
|
-
- [34 — Pillar 2 ContentStreamCorrelator (generalize correlate-v4)](34-pillar2-content-stream-correlator.md)
|
|
65
|
-
- [35 — Universal set production run + glyph provenance (Part 1 close)](35-universal-set-production-run.md)
|
|
66
|
-
- [36 — Per-font coverage audit against universal set (Part 2 master)](36-per-font-coverage-audit.md)
|
|
67
|
-
- [37 — Coverage highlight reporter (missing-glyph visualizer)](37-coverage-highlight-reporter.md)
|
|
68
|
-
- [38 — fontist.org glyph consumer + provenance display](38-fontist-org-glyph-consumer.md)
|
|
69
|
-
|
|
70
|
-
### Pipeline wiring (archive integration)
|
|
71
|
-
|
|
72
|
-
- [40 — fontist-archive-private bin/build uses ucode audit](40-archive-private-uses-ucode-audit.md)
|
|
73
|
-
- [41 — ucode Unicode artifacts → fontist-archive-public bridge](41-ucode-unicode-archive-bridge.md)
|
|
74
|
-
- [30 — Tier 1 font acquisition: specialist fonts](30-tier1-font-acquisition.md)
|
|
75
|
-
- [31 — Universal set production build + coverage validation](31-universal-set-production-build.md)
|
|
76
|
-
|
|
77
|
-
### Sequencing
|
|
78
|
-
|
|
79
|
-
- [22 — Implementation order](22-implementation-order.md)
|
|
80
|
-
- [28 — Implementation order update (TODOs 23-31)](28-implementation-order-update.md)
|
|
81
|
-
- [39 — Implementation order update (TODOs 32-38)](39-implementation-order-update-32-38.md)
|
|
82
|
-
|
|
83
|
-
## Conventions
|
|
84
|
-
|
|
85
|
-
- One concern per file. If a TODO grows past ~250 lines it should split.
|
|
86
|
-
- File numbering is stable; reuse the next free number for additions.
|
|
87
|
-
- Every TODO lists: Goal, Files, Scope, Acceptance, References.
|
|
88
|
-
- Specs use real model instances — never `double()` (global rule).
|
|
89
|
-
- All new lib files use Ruby `autoload` (declared in the immediate
|
|
90
|
-
parent namespace's file) for same-library code. No `require_relative`
|
|
91
|
-
and no `require "ucode/..."` inside the library.
|
|
92
|
-
- No AI attribution in any commit, doc, or comment.
|
|
93
|
-
- Branch naming: `audit/<track-slug>` (e.g. `audit/schema-design`).
|
|
94
|
-
One PR per track unless tracks are tightly coupled.
|
|
95
|
-
- Land PR #1 (`tier1-cmap-audit`) before starting any track in this dir.
|
|
96
|
-
The migration builds on top of the merged RealFonts subsystem.
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
# 01 — Pillar terminology alignment
|
|
2
|
-
|
|
3
|
-
## Goal
|
|
4
|
-
|
|
5
|
-
Fix the inconsistency between the README's "two pillars" claim and the
|
|
6
|
-
actual 4-tier glyph sourcing strategy. The recent commit `24e6bfd`
|
|
7
|
-
("Pillar-2 content-stream correlation fallback") was named correctly;
|
|
8
|
-
the README at `docs/architecture.md`'s "4-tier strategy" section is
|
|
9
|
-
authoritative.
|
|
10
|
-
|
|
11
|
-
## Problem
|
|
12
|
-
|
|
13
|
-
The README currently says (line ~155):
|
|
14
|
-
|
|
15
|
-
> ### The v0.2 plan — two pillars
|
|
16
|
-
> 1. Real character glyphs — extract the subsetted fonts from the PDF.
|
|
17
|
-
> 2. Last Resort placeholders — render directly from the UFO source.
|
|
18
|
-
|
|
19
|
-
This collapses Tier 1 (real-font cmap) and the three PDF-side pillars
|
|
20
|
-
into "two pillars". The actual strategy (per project memory and the
|
|
21
|
-
in-tree code) is four-tier:
|
|
22
|
-
|
|
23
|
-
1. **Tier 1** — real-font cmap (`Ucode::Glyphs::RealFonts`).
|
|
24
|
-
2. **Pillar 1** — PDF-embedded font with `/ToUnicode` (`EmbeddedFonts::Catalog`).
|
|
25
|
-
3. **Pillar 2** — PDF content-stream correlation (`ContentStreamCorrelator`).
|
|
26
|
-
4. **Pillar 3** — Last Resort UFO (`Ucode::Glyphs::LastResort`).
|
|
27
|
-
|
|
28
|
-
The mismatch confuses anyone reading the code (where each tier is
|
|
29
|
-
distinct) vs the README (which merges three of them).
|
|
30
|
-
|
|
31
|
-
## Files to change
|
|
32
|
-
|
|
33
|
-
- `README.md` — replace the "two pillars" section with the 4-tier table.
|
|
34
|
-
Cross-link to `docs/architecture.md` §"The 4-tier glyph sourcing
|
|
35
|
-
strategy" as the canonical reference.
|
|
36
|
-
- `docs/architecture.md` — already correct; no change here.
|
|
37
|
-
- `CLAUDE.md` — has a brief mention of glyph sourcing; align the
|
|
38
|
-
vocabulary with the 4-tier names.
|
|
39
|
-
|
|
40
|
-
## Scope
|
|
41
|
-
|
|
42
|
-
In scope:
|
|
43
|
-
- README rewrite (one section, ~50 lines).
|
|
44
|
-
- CLAUDE.md vocabulary tweak (one paragraph).
|
|
45
|
-
- No code changes.
|
|
46
|
-
|
|
47
|
-
Out of scope:
|
|
48
|
-
- Renaming any code symbol. The current symbols (`RealFonts`,
|
|
49
|
-
`EmbeddedFonts::Catalog`, `ContentStreamCorrelator`, `LastResort`) are
|
|
50
|
-
fine; the names match their function. Only the prose label "tier" vs
|
|
51
|
-
"pillar" needs disambiguation.
|
|
52
|
-
- Updating the commit message of `24e6bfd`. The commit was correctly
|
|
53
|
-
named; do not rewrite history.
|
|
54
|
-
|
|
55
|
-
## Acceptance
|
|
56
|
-
|
|
57
|
-
- `grep -ni "two pillars" README.md` returns no matches.
|
|
58
|
-
- `grep -ni "pillar" README.md` returns matches that fit the 4-tier
|
|
59
|
-
vocabulary (Tier 1 + Pillars 1-3).
|
|
60
|
-
- README's strategy section cross-links to `docs/architecture.md`.
|
|
61
|
-
- No code changes; no spec changes; no changelog entry needed beyond
|
|
62
|
-
the commit message.
|
|
63
|
-
|
|
64
|
-
## References
|
|
65
|
-
|
|
66
|
-
- `docs/architecture.md` §"The 4-tier glyph sourcing strategy"
|
|
67
|
-
- Commit `24e6bfd` (correctly named)
|
|
68
|
-
- Commit `307fda3` (Tier-1 implementation)
|
|
69
|
-
- Memory: `ucode_glyph_extraction_cell_border_bug.md`
|