Skip to content

What counts as public

The hash is one contract; the classes are the other. Every class in src/ is marked either @api or @internal, and ApiBoundaryTest fails the suite if one is marked neither, marked both, or if a public method hands back an internal type — because a type you can reach from a public signature is public whatever its annotation claims.

The public surface is twenty classes:

entry point Formatter
results Digest, LazyDigest, Explain\Explanation, Explain\Rule
configuration Options, Normalization, IndexNormalizer
extension Extension\ClauseRenderer, Extension\RenderedClause
failures Exception\InvalidQueryException, Exception\InvalidOptionException
Monolog Monolog\DigestProcessor, Monolog\SafeDigest
transport Http\DigestingClient, Http\Guzzle\DigestMiddleware, Http\Ring\DigestingHandler, Http\SearchObserver, Http\ObservedSearch, Http\LoggingObserver

Everything else — the parser, the tree, the renderers, the canonicaliser, the hasher, the CLI command — is @internal. Not out of secrecy: those are exactly the classes that change whenever a query type is promoted. Freezing them would mean every improvement to the rendering is a major release, and the library would stop improving. Depend on them and an ordinary patch may move under you.

This matters because it is the half of a 1.0.0 that cannot be walked back: widening a public surface later is free, narrowing one is not.