Annotations Audit — Developer Reference
Developer-focused reference. For module overview, pages, and Drush commands see README.md.
CoverageService
CoverageService (annotations_audit.coverage_service) is the public API for coverage data. Any module that needs to act on coverage — workflow conditions, CI checks, export enrichment — injects this service directly.
$coverage = $coverageService->getCoverage();
// Returns: array<string, array{
// target: AnnotationTargetInterface,
// status: 'complete'|'partial'|'empty',
// missing: array<string, string[]> // [type_id => ['overview', 'field_name', ...]]
// }>
$entry = $coverageService->getCoverageForTarget($target);
$score = $coverageService->getScore($coverage);
// Returns: array{
// complete: int, total: int, percent: int,
// filled_tracked: int, total_tracked: int,
// filled_optional: int, total_optional: int,
// }
$affects = $coverageService->affectsCoverage($annotationType);
Coverage statuses:
| Status | Meaning |
|---|---|
complete |
All status-affecting annotation types filled at target level and for all included fields |
partial |
Target-level primary type filled, but gaps remain at field or secondary type level |
empty |
Primary status-affecting type is blank at target level |
When annotations_workflows is installed, only published annotations count as filled. Without it, the published filter is a no-op.
ScanService
ScanService (annotations_audit.scan_service) handles snapshot persistence and diff logic. Inject it directly to build on the audit scan data.
// Run discovery — returns array<target_id, data>
$result = $scanService->scan();
// Snapshot
$scanService->saveSnapshot($result);
$stored = $scanService->loadSnapshot();
// Diff
$diff = $scanService->computeDiff($current, $stored);
// Returns: ['added' => ..., 'removed' => ..., 'changed' => ...]
$hasChanges = $scanService->diffHasChanges($diff);
$timestamp = $scanService->getLastScanTimestamp(); // ?int
// Accumulated changes (since last waypoint)
$changes = $scanService->getAccumulatedChanges();
$scanService->clearAccumulatedChanges();
$scanService->mergeNewChanges($diff); // returns only newly added entries
// Scope drift — fields in Drupal but not in any target's scope
$drift = $scanService->getScopeDrift();
// Returns: array<target_id, string[]>
Each scan entry is keyed by {entity_type}__{bundle}:
[
'entity_type' => 'node',
'label' => 'Article',
'bundle' => 'article',
'fields' => [
'field_body' => ['label' => 'Body', 'type' => 'text_long', 'required' => false, 'cardinality' => 1, 'description' => ''],
],
]
Performance note
getCoverage() executes one DB query per target. At 100+ targets this becomes significant on every page load. The intended fix at scale is cron-driven snapshot storage with cached results. Deferred until target counts warrant it.