Close the discovery loop described in docs/checker-discovery.md: entries
published in commit 3 now feed consumer checkers, and their observations
flow back to the original producer.
Three tightly-coupled changes:
- CheckerOptionsUsecase gains an optional DiscoveryEntryStorage
dependency (WithDiscoveryEntryStore). When a checker declares
AutoFill="discovery_entries" on an option,
BuildMergedCheckerOptionsWithAutoFill populates it with the entries
stored for the target: all producers, no host-side filtering by
Type. The method also returns the concrete list of entries injected
so the engine can persist lineage for them.
- CheckerEngine records a DiscoveryObservationRef per (entry, obs key)
tuple after the snapshot is stored. The ref namespaces back to the
*producer* (ProducerID, Target, Ref) while carrying the consumer's
key and the snapshot pointer, so a later GetRelated from the
producer can reach the consumer's observation in one lookup.
- ObservationContext exposes SetRelatedLookup (called once per run by
the engine) and implements GetRelated on top of the installed
closure. The engine's closure walks the producer's published
entries, resolves each ref's observation refs, loads the snapshots,
and materialises []RelatedObservation. Stale refs (entry gone,
snapshot TTL'd) are skipped silently: implicit GC, as the doc
permits.