Add internal events for the v3 sync run outcomes
What does this MR do and why?
The v3 sync path has no instrumentation, so a run that skips a registry or aborts before any PDS call is only visible by reading logs. This adds one internal event per terminal outcome of a v3 run, for both datasets on the shared service: sync_pmdb_v3_<data_type>_<outcome> over malware_advisories and licenses, fifteen outcomes each, so an outcome is queryable by name without filtering on a property. label carries the purl_type everywhere except aborted_no_token, which precedes any registry. delta_backlog is a measurement rather than an outcome and carries the number of delta archives PDS offered in value, so a caught-up instance (zero) reads differently from one PDS never answered for (no event). A SYNC_OUTCOMES allowlist gates every emitted name, and a spec asserts a definition file exists for each (data type, outcome) pair, so a new dataset cannot emit an event with nothing behind it. started is not tracked, a run that never reaches an outcome shows up as a missing outcome.
A PDS 400 was also indistinguishable from an answered request with nothing in it. Pds#fetch returned nil without raising, so a rejected bulk /delta reported delta_up_to_date for every registry, and on the individual path a rejected /delta did the same while a rejected /all reported full_completed. fetch now returns an empty hash on a 204, PDS having answered with nothing, and nil on a 400, and delta_files_for and data_after pass that through: the bulk path tracks bulk_delta_failed and stops before the per-registry loop, and the individual path tracks <mode>_failed. Registries PDS omits or lists under not_supported also stop recording a backlog of zero, which read as fully caught up rather than not measured.
Relates to
- Relates to #602417
- Success metrics: #627683
- Pattern reference: !237975 (merged) (#600562 (closed))