# Why TextProv publishes selectors instead of PUA text

TextProv has two ways to encode the same provenance state. Both are useful, but
only one is intended to cross an uncontrolled boundary such as a published
file, a web page, a clipboard, or an archive.

The distinction becomes clear in a practical case: opening marked text in Zed
on macOS.

## A marked letter in two forms

Suppose the letter `A` was generated by AI. In selector encoding, TextProv
stores the ordinary letter followed by its AI selector:

```text
U+0041 U+E0101
   A     AI selector
```

The sequence means “the grapheme `A`, with AI provenance.” `U+E0101` is a
standardized variation-selector code point, but TextProv's use of it is a
private convention rather than a Unicode-registered variation sequence.

In PUA encoding, registry version 1 can replace that sequence with one
Supplementary Private Use Area-B code point:

```text
U+100041
 AI form of A in the TextProv registry
```

The two forms carry the same state to a TextProv decoder. They do not fail in
the same way when the decoder or provenance font is absent.

## The selector form keeps the text intact

A consumer that does not understand TextProv can ignore or consume the selector
and still render `A`. The provenance decoration may disappear, but the base
text remains available as an ordinary Unicode character.

That fallback is the reason selector encoding is the interchange form. A
recipient does not need the TextProv registry merely to read the sentence. The
text can pass through systems that know nothing about the provenance convention
without replacing every supported character with an unknown private one.

The fallback is deliberately conservative: failure to display provenance
becomes plain, legible text rather than damaged text.

## The PUA form delegates meaning to a private agreement

Unicode assigns no public character semantics to a Private Use Area code
point. Its meaning comes from an agreement among the producer, font, and
decoder. Under TextProv's registry, `U+100041` means the AI form of `A`; outside
that agreement, it is only a private code point.

A consumer without the matching P+ font may show a missing-glyph box. A
consumer without the registry cannot infer that the code point stands for `A`.
Copying it preserves the private code point, not the ordinary letter. Search,
indexing, speech output, spell-checking, and other text operations therefore
cannot be assumed to recover the base text.

This does not make PUA invalid. It makes PUA suitable for a controlled display
workflow, where every participant has agreed on the mapping and font, rather
than for durable interchange among unknown consumers.

## Why Nerd Fonts can use PUA

Nerd Fonts uses PUA code points for icons because its contract includes a
patched font. A prompt, status line, or editor UI asks that font to draw an icon
at a private code point. If the font is absent, a missing glyph is an accepted
failure mode; there is usually no underlying prose character that must remain
readable.

That is the same mechanism but a different requirement:

- A Nerd Fonts icon is intentionally font-dependent visual content.
- A TextProv mark annotates ordinary text whose words must survive without the
  provenance renderer.

Nerd Fonts' use of PUA demonstrates that PUA is effective inside an agreed font
ecosystem. It does not give a PUA assignment universal Unicode meaning or make
it portable outside that ecosystem.

## What Zed on macOS reveals

The P+ provenance font contains mappings from a base-plus-selector sequence to
a decorated glyph. HarfBuzz follows those mappings. Zed on macOS shapes text
through CoreText, and a direct CoreText test did not select the decorated glyph
for `<base, U+E0101>`. CoreText consumed the selector and emitted the plain base
glyph. The text stayed readable and aligned, but the sawtooth provenance mark
disappeared.

The extra spacing and green underlines observed in Zed are a separate editor
display artifact. Zed 1.18.1 classifies `U+E0100` through `U+E01EF` as invisible
characters. If a highlighting boundary leaves a selector as a standalone
grapheme in a highlighted chunk, Zed's invisible-character path can substitute
`U+2007 FIGURE SPACE` and decorate it. This changes the display, not the buffer
or saved file. The source path is known; the condition that caused the observed
chunk boundaries has not been reproduced.

PUA avoids the known CoreText selector limitation in a direct test because the
private code point maps straight to the decorated glyph. Zed also does not
classify TextProv's Supplementary PUA-B assignments as the invisible selectors
above. The complete Zed path has not been verified, so PUA remains a candidate
local workaround rather than a compatibility guarantee.

This is a useful illustration of the trade-off. The selector form failed
visually but preserved the letter. The PUA form may improve rendering in that
controlled editor setup, but it does so by replacing the letter with a code
point that requires private knowledge to decode.

## Try both encodings in an editor

Open these UTF-8 files side by side in Zed, VS Code, or another editor:

- [`examples/provenance-vs.txt`](examples/provenance-vs.txt) contains one
  selector-encoded sample.
- [`examples/provenance-pua.txt`](examples/provenance-pua.txt) contains the same
  sample encoded with registry version 1's PUA mappings.
- [`examples/provenance-vs-and-pua.txt`](examples/provenance-vs-and-pua.txt)
  places both encodings in one file for a direct comparison.

Each file keeps its instructions as ordinary unmarked text. This provides a
readable control and lets the PUA sample demonstrate its missing-font behavior
without making the whole explanation unreadable. Compare the files first with
a normal font, then select the matching P+ font. The files state the expected
outcomes and distinguish verified behavior from editor paths that have not yet
been tested.

Use the included commands to inspect the stored provenance independently of
what the editor draws.

## Publishing and local display are different boundaries

Keep selector-encoded text as the canonical copy. A local tool may derive a PUA
copy for an editor or renderer that has the matching font:

```sh
python3 -m textprov -o document-pua.md convert --from vs --to pua document.md
```

Registry version 1 has PUA assignments only for the AI state and supported base
characters in `U+0021`–`U+00FF`, excluding whitespace, control, and format
characters. Unsupported grapheme clusters remain selector-encoded, so a
converted file may contain both forms.

Do not publish the derived PUA copy as the canonical document. Convert it back
to selector encoding before it leaves the controlled workflow. This keeps the
ordinary Unicode text available even where provenance rendering is absent.

## Evidence and limits

The CoreText and Zed behavior above is documented in the Nerd Fonts fork's
[Zed rendering notes](https://github.com/delano/nerd-fonts/blob/main/src/glyphs/provenance/zed-about.md).
The repository has not measured all expected effects of PUA on find-in-page,
clipboard behavior, or screen readers; [ADR 0008](adr/0008-do-not-publish-pua-to-the-web.md)
records those points as reasoning rather than experimental evidence. The
normative encoding and conversion rules are in the [TextProv protocol
specification](../SPEC.md#encodings).
