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-three classes:

entry point Formatter
results Digest, Kind, LazyDigest, Explain\Explanation, Explain\Rule
analysis Analysis\Report, Analysis\Shape
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.