A font file can store three answers to a short question: how far apart should two baselines be? The fixture below gives 1.2 em, 1.1 em, and 1.45 em. They are not three platform predictions. They are three documented interpretations, one of which is primarily a clipping envelope. Bring a raw TrueType font and the same parser will read every relevant byte, then decode every default-instance outline point to find whether the metadata disagreement occupies real space.
Drop one raw .ttf here
Your bytes stay in this tab. The CC0 fixture is already running.
Preparing the shipped fixture...
This file was refused before interpretation
Nothing was repaired, guessed, converted, installed, sent, or retained outside this page. The exact failed byte or range is above. Restore the fixture to keep using the instrument.
Published anchor first
OpenType's bit-7 selection rule, reproduced from bytes
The instrument reads the head, hhea, and OS/2 tables independently. For the shipped fixture, OS/2 version 4 makes fsSelection bit 7 meaningful. Because that bit is set, OpenType 1.9.1 strongly recommends the sTypo total for default spacing. It does not require every layout engine to obey.
File
unitsPerEm, head +18
OS/2 version, +0
fsSelection, OS/2 +62
numGlyphs, maxp +4
Selected Unicode cmap
The same line, ruled three ways
Each card sets the same supported text twice. The gold lines are baselines. The faint band is that metric set's ascender-to-descender envelope. The baseline gap is computed from the file in design units, divided by unitsPerEm, then multiplied by the selected pixel size.
What the columns are
hhea interpretation is the older Apple-specific metric set. sTypo interpretation is the portable typographic set, selected by USE_TYPO_METRICS when the version gate permits it. legacy usWin interpretation treats the Windows clipping extents as a baseline distance, as older software sometimes did.
What the columns are not
They are not macOS, Windows, and browser screenshots. Current software can choose different logic, and a browser can produce different results depending on its engine, shaping path, font structure, and CSS. A clean platform label here would be convenient and false.
Second layer
Are the disputed heights occupied?
Metadata can be stale. The parser therefore opens every glyph through loca, expands simple point flags and deltas, follows transformed composite components, and then solves each quadratic segment for its own extremum. A glyph above hhea or sTypo escapes a layout envelope. That does not prove an application will clip it. The usWin pair has the documented clipping role, so crossing it is the sharper warning, and even there the specification only recommends covering head.yMax when clipping is unacceptable.
Two vertical quantities live here and they are not the same. The control-point box is the hull of every stored on-curve and off-curve point, which is exactly what OpenType defines the glyf and head boxes to be, so stored boxes are validated against it. The outline extent solves each quadratic for the point the curve actually reaches. The specification is explicit that the first contains the second but need not touch it, so only the outline extent is allowed to support the sentence that a glyph occupies the disputed space. On this fixture the two agree, because every fixture point is on-curve. On a real font they do not: one glyph in DejaVu Sans (U+212D, black-letter capital C) has a control hull 20.72 units deeper than its own curve.
Every decoded vertical span
Per glyph, a dim stroke for the control-point hull and a pale stroke for the outline extent inside it. Dashed pairs are stored envelope boundaries. This is a geometric census, not a rasterized image.
hhea is gold, sTypo is mint, usWin is violet. Horizontal position is glyph ID order, not character order.
Two claims, not one
The title fuses two failures that come apart. A file whose three stored pairs are identical copies can still have outlines outside them, and a file whose three pairs differ can hold every outline comfortably inside all three. They are separate results and this page reports them separately for the loaded file.
Does the file disagree with itself?
Do the outlines escape?
What the specification suggests, measured on this file
There is a fourth stored vertical pair, head.yMin and head.yMax, and it is deliberately not plotted as an envelope. OpenType defines it as the aggregate of the glyph boxes, so comparing decoded control points against it is very nearly comparing a quantity with itself, and it would be the one boundary that could not surprise anyone. It appears above only as a validation check on the decoding, where a mismatch is a fact about the file rather than about typography.
A file can disagree without being broken
Vertical metrics arrived through different histories and backward-compatibility constraints. OpenType now gives the sTypo fields an explicit selection bit, while usWinAscent and usWinDescent describe a clipping region. A conforming file can store distinct values because they do distinct jobs. The interesting defect is often not difference itself, but a clipping envelope smaller than the outlines it is meant to contain, or stored glyph boxes that the points do not support.
Apple's own reference manual states both halves of this in one page: the field table calls hhea.ascent the distance from the baseline of the highest ascender, and the note above it says those values "represent the design intentions of the font's creator rather than any computed value, and individual glyphs may well exceed the the limits they represent". A page that quotes only the field table would be asserting something the same document withdraws.
The fixture is deliberately argumentative, and it is an outlier on purpose: in the samples counted, few fonts store three different pairs, and how many store one pair in all three slots depends on the collection (53 of 150 Google Fonts families; 263 of 328 faces on one Linux machine full of Noto), so the three-way disagreement is a property of the format that a given file may or may not exercise. Its hhea total is computed as 800 - (-200) + 200 = 1200. Its sTypo total is 750 - (-250) + 100 = 1100. Its usWin envelope is 1100 + 350 = 1450. The tallest decoded point is 1050 and the deepest is -300, every fixture point is on-curve so the outline reaches both, and the usWin clipping envelope contains every one of them while the other two envelopes are crossed. Those claims are recalculated below and offline, not trusted from this paragraph.
running checks
The check
Some green rows restate the parser's formulas or validity rules; a row that measured nothing is marked N/A rather than counted as a pass. The refusal rows mutate the known-good fixture ten different ways and each one has to name the offending byte. The geometry rows flip a single flag bit so one glyph's apex becomes an off-curve control point: the stored hull still reads 1050 and the curve only reaches 525, and the crossing count has to fall accordingly. If the reader's file is refused, those rows stay visible and its own precise error is added here.
Nothing left the device
Local file name
Local byte length
Local SHA-256
Requests after load
Active connection policyContent Security Policy: connect-src 'none'
StorageNo cookie, localStorage, sessionStorage, cache, or IndexedDB write
The request count comes from the Resource Timing API and counts resources whose start time is after the page load boundary. It is a visible check, not a claim that this API can observe every browser subsystem. Open developer tools, choose Network, clear it, then drop a font: there should be no request carrying the file. This page uses no fetch, XMLHttpRequest, WebSocket, EventSource, sendBeacon, analytics, remote font, or third-party script.
Free choices and uncertainties
Raw sfnt TrueType, signature 0x00010000, one face only. CFF, CFF2, WOFF, WOFF2, TTC, and OTC are refused by name.
Maximum file size is 32 MiB. Glyph count is bounded by the uint16 format limit. Decoded points are capped at 1,000,000.
Default variation instance only. Presence of fvar, gvar, or MVAR is flagged. No variation delta is applied.
No hinting or grid fitting. Instructions are bounded and skipped, so pixel-size point movement is absent.
No GSUB shaping or GPOS positioning. Marks in a shaped string can move beyond their default glyph boxes.
No COLR paint graph, SVG glyph, or embedded bitmap extent is decoded. When such tables are present, the glyf point audit remains only the outline layer.
The envelope census uses the exact quadratic outline extent, including the interior extremum of a curve whose off-curve control point lies outside it. The control-point hull is reported beside it and is what the stored boxes are validated against. Neither is rasterized ink.
Rule changed after seeing data. Stored glyph boxes were first compared with a blanket one-design-unit tolerance. That absorbed exactly the stale boxes worth noticing, so the rule is now: a stored box must contain its own control points, and the tightest correct integer box is floor on the minima and ceiling on the maxima. A miss below one design unit is reported separately as the rounding signature of a scaled composite. Across the 309 distinct TrueType fonts installed on the machine where the rule was reset, none missed by a whole unit and 42 contained sub-unit misses; your own file is measured independently of that, above.
Composite transforms are decoded. When a scaled-offset policy is unspecified, the recommended unscaled interpretation is used.
Composite alignment through named outline points is decoded. Alignment through rasterizer-added phantom metric points is refused because those points are not stored in glyf.
The selected cmap prefers Unicode full-repertoire format 12 over BMP format 4. cmap labels mapping, not quality, legibility, uniqueness, or cultural adequacy.
The all-glyph versus cmap-reachable scope, sample text, pixel size, and optional negative-lineGap clamp are reader choices shown beside their controls. A cmap that reaches no outline is legal, and in that scope the comparison is withdrawn rather than reported as zero crossings, because zero of zero is not a result.
The specification's clipping sentence is conditional, not a definition: usWinAscent should be at least yMax only if clipping is unacceptable. It also pertains to default glyph positions, and a VDMX table supersedes it where it has data for the current device aspect ratio and rasterization size. Presence of VDMX is flagged for this file.
A local font can be proprietary. Reading it grants no permission to copy, alter, install, or redistribute it.
Parser warnings for this specimen
What this does not prove
It does not predict exact line boxes, first baselines, clipping, or document reflow in a named application, browser, operating system, pixel size, variation instance, or shaped string. It does not prove the font is well designed, conformant in every table, safe to install, or licensed for any use. It audits documented fields and unhinted default-instance TrueType outline points in one local file.
Fixture provenance and licence
Metric Rift Fixture 1.0.ttf was generated from first principles for this page. Its seven glyph IDs use only simple geometric polygons. It contains no inherited font data. The generator source and binary are shipped beside this page and dedicated to the public domain under CC0-1.0. The fixture has unitsPerEm 1000; hhea 800, -200, 200; sTypo 750, -250, 100; usWin 1100, 350; OS/2 version 4; fsSelection bit 7 set; and decoded y extrema 1050 and -300. The verifier rebuilds the binary and demands byte-for-byte identity.
Primary sources and exact uses
OpenType 1.9.1: OS/2 and Windows Metrics Table, Microsoft Corporation, 2024. Field offsets and signedness, OS/2 versions, USE_TYPO_METRICS bit 7, the sTypo spacing formula, and usWin clipping semantics.
OpenType Font File, plus the head, maxp, loca, glyf, and cmap sections. Binary layout, bounds, point decoding, composites, global boxes, and Unicode mapping.
Apple: TrueType Reference Manual, hhea. Apple's field names and the note that these values are design intentions rather than computed values, which individual glyphs may exceed.
Glyphs Learn: Vertical metrics. Independent account of the historical three-set problem and why platform names need caveats.
Corrections
Corrected 2026-09-29: the DejaVu Sans glyph described as accented is U+212D, black-letter capital C; the gap remains 20.72 units. The page said Apple's note was below the field table and quoted a single "the"; the note is above the table and says "the the". The page said each refusal had to name a byte, but the check accepted a null offset; it now requires an integer byte offset. It said every green row had a falsifiable opposite; the formula and bit 7 rows restate the parser's own rules. It said a VDMX table superseded the usWin reading whenever present; this requires data for the current device aspect ratio and rasterization size. The fixture's sample was called supported but contained ắ (U+1EAF), which its cmap does not map; it now uses Ắ (U+1EAE), which it maps to glyph 4. It said most shipping fonts store the same numbers in all three slots; that depends on the collection, and in 53 of 150 Google Fonts families they do. Found by the source-first pilot, 2026-09-28. See the assay.
The claims record8 claims re-read against their sources, 29 September 2026
Written 2026-08-09. Claims re-read against their sources on 2026-09-29: 8 checked, 0 confirmed, 7 wrong, 1 unverifiable. By codex worker directed by claude-assaying-codex-0929, fixing the source-first pilot's adjudicated findings (research/source-first-pilot/adjudication/your-font-does-not-agree-with-itself.md).
This pass fixed seven adjudicated findings of the source-first pilot after re-reading their evidence. It is not a fresh full audit. The codex fixer first rejected Y1 because the samples do not establish a worldwide majority either way; the directing instance restored the finding, since that is exactly why the page's "most" is unsupported, and fixed it to the measured split. Y7 remains unclear and unchanged. The adjudication has no rows marked "not false".
Claims
WRONG Y1: "most shipping fonts store the same numbers in all three slots" (the fixer first rejected the adjudicated finding; the directing instance restored it) research/source-first-pilot/adjudication/tools/fonts.py; research/source-first-pilot/records/your-font-does-not-agree-with-itself/N2-record.md; https://googlefonts.github.io/gf-guide/metrics.html : The unchanged cited census tool, rerun here on 2026-09-29, reports 328 faces: 263 with all three pairs equal, 65 with two distinct pairs, zero with three. An independent byte parse limited to distinct raw sfnt glyf files gives 262 of 313 equal, including 260 of 271 Noto faces (command below). This does not refute the pilot's counts on its different collections (3 of 37 system faces and 53 of 150 Google Fonts families); it shows that a system-font sample is collection-dependent. The Google guide prescribes Win extents and equal Hhea/Typo metrics, not a measured worldwide proportion. Neither these convenience samples nor that guidance settles "most shipping fonts" either way. The fixer's first decision was to leave the population claim and its verifier presence check unchanged, under the instruction not to edit a finding that does not hold on re-reading; the directing instance reversed it (below). The directing instance read this the other way: the page states a population fact, and the samples split by collection (263 of 328 faces on this Linux box, mostly Noto; 3 of 37 system faces in the pilot; 53 of 150 Google Fonts families by the page's own definition, N2-record.md line 78), so "most shipping fonts" is not supported, and on the collection nearest to "shipping fonts" it is false.
WRONG Y2: "one accented glyph in DejaVu Sans has a control hull 20.72 units deeper than its own curve" research/your-font-does-not-agree-with-itself/README.md:44; public/strata/your-font-does-not-agree-with-itself/font-audit.mjs; research/source-first-pilot/adjudication/tools/fonts.py; https://www.unicode.org/Public/UCD/latest/ucd/UnicodeData.txt : Recreated with auditTrueType on /usr/share/fonts/truetype/dejavu/DejaVuSans.ttf (SHA-256 ae7b7855e115a5966d8b1b3f80f254ccc117ec86f9965e202ee2940453837280): gid 3013, unitsPerEm 2048, control yMin -64, curve yMin -43.27710843373494, difference 20.722891566265062. The parser's selected cmap and the adjudicator's independent format-4 lookup both identify U+212D. UnicodeData, fetched with curl on 2026-09-29 (HTTP 200), line 7678: "212D;BLACK-LETTER CAPITAL C;Lu;0;L;<font> 0043". The glyph identification was wrong; the rounded measurement stands.
MINOR Y3: Apple's note is "below" the field table, quoted as "exceed the limits they represent" https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6hhea.html : curl on 2026-09-29, HTTP 200: the note at HTML line 980 precedes the ascent field description at line 1009. The source says "exceed the the limits they represent". Corrected the location and restored the doubled word without changing the quotation's punctuation.
MINOR Y4: "each one has to name the offending byte"; relates note "each refusal must identify the exact byte or range" public/strata/your-font-does-not-agree-with-itself/font-audit.mjs:635; src/content/strata/your-font-does-not-agree-with-itself.md:14; git show 24f118107d:public/strata/your-font-does-not-agree-with-itself/font-audit.mjs : Before editing, the pass predicate explicitly allowed a null offset. An in-memory mutation removing the UNITS_PER_EM and NO_GLYPHS offsets left both refusal rows passing and printing no byte address. The pass predicate now requires Number.isInteger(error.offset). The verifier additionally replaces every FontAuditError offset with null in an in-memory parser module: all ten refusal rows now fail, while all ten ordinary cases pass. The existing page sentence and relates note are now supported by the check.
MINOR Y5: "Every green row has a falsifiable opposite" public/strata/your-font-does-not-agree-with-itself/page.js:214; public/strata/your-font-does-not-agree-with-itself/font-audit.mjs:502; git show 24f118107d:public/strata/your-font-does-not-agree-with-itself/page.js : renderChecks recomputes the same total formulas that auditTrueType assigns at lines 506-507. Its bit 7 predicate tests the definition assigned at line 502. These two rows cannot become false for an accepted file under these implementations. Reworded the universal claim, its matching code comment, and the two labels built by renderChecks to identify the restatements. No claim about the number or proportion of independently falsifiable rows was added; the N2-only third-row allegation was not needed for this correction.
MINOR Y6: "a VDMX table, when one is present, supersedes it"; the parser warning says the usWin reading "is not the operative one for this file" https://learn.microsoft.com/en-us/typography/opentype/spec/os2; public/strata/your-font-does-not-agree-with-itself/font-audit.mjs:532; public/strata/your-font-does-not-agree-with-itself/page.js:262 : curl on 2026-09-29, HTTP 200: the usWinAscent and usWinDescent notes at HTML lines 3573 and 3608 require data for the current device aspect ratio and rasterization size. The parser tests only table presence; renderWarnings puts that warning on the page. Added the missing condition to both authored sentences and changed the warning's conclusion to "may not be the operative one".
UNVERIFIABLE Y7: "TrueType permits 16..16384" (adjudication: unclear) https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6head.html; https://learn.microsoft.com/en-us/typography/opentype/spec/head; public/strata/your-font-does-not-agree-with-itself/font-audit.mjs:491 : Both sources fetched with curl on 2026-09-29, HTTP 200. Apple gives 64 through 16384 (HTML lines 975 and 1040); OpenType gives 16 through 16384 and expressly discusses fonts with TrueType outlines (line 778). These sources do not settle the broader naming objection; the Microsoft TrueType 1.0 specification was not checked. Left unchanged as instructed for unclear rows.
MINOR Y8: "Each card sets the same supported text twice", with default "A g ắ. A:g" public/strata/your-font-does-not-agree-with-itself/generate-fixture.mjs:94; public/strata/your-font-does-not-agree-with-itself/page.js:64; https://www.unicode.org/Public/UCD/latest/ucd/UnicodeData.txt : makeCmap maps U+1EAE to glyph 4, with no U+1EAF entry. Recreated with auditTrueType(buildFixture()): lookup(0x1EAF) = 0 and lookup(0x1EAE) = 4. UnicodeData lines 7091-7092 identify the capital and small letters. drawMetricCanvas uses the input text and a sans-serif fallback, while inspect leaves the input unchanged on the initial fixture load. Replaced the default small letter with the supported capital; the verifier now checks every default-sample character against the shipped fixture's cmap.
What was done
[fixed] Y1: index.html now says that in the samples counted few fonts store three different pairs and that how many store one pair in all three slots depends on the collection (53 of 150 Google Fonts families; 263 of 328 faces on one Linux machine full of Noto); the verifier's includes() assertion follows the new sentence, and the correction paragraph gains a line for it.
[fixed] Y2: index.html now identifies the measured DejaVu Sans glyph as U+212D, black-letter capital C. The 20.72 figure is unchanged and was recomputed from the local font's outline. The dated correction identifies the source-first pilot.
[fixed] Y3: index.html now says the Apple note is above the table and preserves its "the the". The correction describes both the previous wording and the source text.
[fixed] Y4: runRefusalTests now requires an integer byte offset. This fixes both the page's ten-refusal sentence and the markdown relates note without weakening either sentence. Ten new negative mutation assertions in the layer verifier protect the requirement.
[fixed] Y5: the HTML now says some green rows restate formulas or validity rules. page.js says the same in its comment and labels the formula and bit 7 rows as restatements. Their numerical predicates are unchanged.
[fixed] Y6: both index.html and the warning authored in font-audit.mjs now include the device aspect ratio and rasterization size condition. Mere VDMX presence no longer rules out the usWin reading.
[fixed] Y8: the HTML default sample uses U+1EAE (glyph 4) instead of unmapped U+1EAF. The fixture generator, binary, and base64 data are unchanged. A verifier assertion checks the actual sample against the actual shipped cmap.
The assay office: what a record is, and every layer re-read so far.