Files
zeekay feafb592a6 build: refuse to publish a face that is not ours
The estate carried Geist under our name in four repositories. Those files said
family "Zen" and manufacturer "Hanzo AI, Inc." while their vendor tag was still
VRCL and nameID 0 named one holder — a partial relabelling, which answers "Zen"
to every question a stylesheet, a grep or a font menu asks. Family alone cannot
tell you whose bytes these are; vendor and notice can.

identity.py holds that answer once. name.py and notice.py write identity into a
binary and each had its own copy of the notice text, free to drift; they now
read it from one place. The same definition read backwards is the check, and
copy-npm-fonts ends with it, so a face becomes something the package would
publish and is refused in the same step. All 87 faces pass.

Two things the check learned from being tested rather than assumed. A static
cut outside the four styles a family can group puts its weight in nameID 1 and
the shared family in nameID 16, so "Zen Thin" is correct and 16 is the field to
read. And the notice lives in a Windows record and a Mac one: reading only the
record fontTools hands you passes a face that rewrote just the other one, so
every nameID 0 record must carry both holders.
2026-08-28 16:32:19 -07:00

61 lines
1.9 KiB
Python

"""Put the upstream copyright line back on the built families.
`name.py` names the hand-exported Zen Pixel cuts and writes nameID 0 as the
upstream notice above ours, because OFL §2 binds each copy of the Font Software
to the notice and a .woff2 served to a browser IS a copy travelling alone. The
fontmake-built families take the other path — their fields come from the Glyphs
sources via `scripts/set-fontinfo.py` — and that path wrote only our line, so
Zen and Zen Mono shipped without the notice the licence at the root already
carries. This puts them in agreement.
Sources are fixed too (set-fontinfo.py), so a rebuild produces this directly;
this exists for the binaries already built and committed.
python3 packages/zen/scripts/notice.py
Idempotent: a file already carrying both lines is left alone.
"""
import pathlib
import sys
from fontTools.ttLib import TTFont
from identity import NOTICE, OURS, UPSTREAM
ROOT = pathlib.Path(__file__).resolve().parents[3]
def fix(path: pathlib.Path) -> bool:
f = TTFont(str(path))
have = f['name'].getDebugName(0) or ''
if UPSTREAM in have and OURS in have:
return False
f['name'].setName(NOTICE, 0, 3, 1, 0x409)
f['name'].setName(NOTICE, 0, 1, 0, 0)
f.save(str(path))
return True
def main() -> int:
roots = [ROOT / 'fonts', ROOT / 'packages' / 'zen' / 'dist' / 'fonts']
seen = fixed = 0
for r in roots:
if not r.is_dir():
continue
for path in sorted(r.rglob('*')):
if path.suffix not in ('.otf', '.ttf', '.woff2'):
continue
seen += 1
if fix(path):
fixed += 1
if not seen:
print('no built faces found — run `make build` first', file=sys.stderr)
return 1
print(f'{fixed} of {seen} faces gained the upstream notice'
if fixed else f'all {seen} faces already carry both notices')
return 0
if __name__ == '__main__':
sys.exit(main())