Audits

An audit runs the checks against the index and records what it found. Nothing changes until you ask it to.

Quick and deep

A quick audit is set comparisons in SQL. It finds orphaned rows, unindexed elements, partly indexed elements, stale field rows, rows for attributes an element type no longer claims, elements with no keywords at all, rows that hit the storage ceiling, and Craft’s own pending index backlog. It does not load a single element, and finishes in seconds on a large site.

A deep audit does all of that, and then reads each element, works out the keywords Craft would write for it right now, and compares them with what is stored. It is the only way to catch content that changed without the index being told:

  • an import that wrote to the database directly
  • a plugin update that changed how a field produces keywords
  • a queue that was failing quietly

It costs one element load apiece. That is why it runs on the queue by default and stops at a configurable number of elements per type, newest first.

QuickDeep
Loads elementsNoYes
Finds keyword driftNoYes
Typical runtimeSecondsMinutes
Runs on the queueNoYes, by default
Safe on productionYes — read-onlyYes, within the deep limit

Scoping a run

The new-audit form takes three narrowings, all optional:

  • Sites — all of them, or particular ones. Worth using on a multi-site install where only one site is suspect.
  • Element types — all, or particular classes. A site with a million Commerce order elements can leave them out of every routine audit.
  • Checks — all enabled ones, or a named subset. Useful when you are chasing one specific problem and want the answer in seconds.

The settings hold the defaults for all three, plus a permanent list of checks and element types to skip.

Reading the report

Every finding carries a severity:

SeverityMeans
CriticalContent that cannot be found, or index rows that will never be cleaned up
WarningSomething is out of step and searches are affected
NoticeWorth knowing, working as designed

Severity belongs to the finding, not to the check. The same check can report a critical and a notice in one run — empty keywords on a normal entry is a fault, and empty keywords on a Matrix block is how Craft works.

Counts, and why the list is capped

Every check runs a COUNT for its headline and a limited query for the detail. A site with 400,000 orphaned rows gets one line saying so and a sample beneath it, not 400,000 rows in the report. The cap is maxIssuesPerCheck, 500 by default, and the overflow is shown as an and N more line.

The count is what you act on. A fix works from its own fresh detection pass, not from the report, so a capped list never means a partial repair.

Fixing

Findings that Holmes can do something about carry a fix — usually Reindex or Delete rows. You can apply one, or apply all of a check’s findings at once. Fixes are covered in Repairs & sync.

History and retention

Finished audits are kept so you can compare runs — the useful question after a deploy is usually not what is wrong but what is newly wrong. Holmes keeps the last 20 by default and prunes older ones, with their findings, after each run. Set retentionCount to 0 to keep everything.

From the console

# a quick audit of everything
php craft holmes/audit

# deep, with no cap on elements per type
php craft holmes/audit --mode=deep --deep-limit=0

# just the two checks you care about
php craft holmes/audit --checks=orphaned-rows,unindexed-elements

# audit and repair in one go
php craft holmes/audit --fix

# what checks are registered, and which are deep
php craft holmes/audit/checks

# re-read a stored report
php craft holmes/audit/show 12

In CI

--fail-on=critical makes the command exit non-zero when it finds something at or above that severity, which is what you want after a deploy or a content migration:

php craft holmes/audit --mode=deep --fail-on=critical