Greater Atlanta's IT partner since 1989

Operations guide

Tuning

Tune AJC Form Guard's spam threshold and checks, read its decisions, and manage a fleet policy.

Version 1.2.1 · WordPress 6.0+ · PHP 8.1+ · Licensed GPL-2.0-or-later

The scoring model

Each of the ten checks contributes points. When the total reaches the flag threshold (50 by default), the submission is filed as spam.

   0 ─────────────────── 50 ──────────────── 120 ───────────► 300
        accepted        FLAG              REFUSE
                    (Spam folder,      (off by default,
                     no notification)   leaves no record)

Weights are deliberately set so that no circumstantial check can flag a submission on its own. A throwaway email address, a burst of submissions, an unusual number of links — each has an innocent explanation, and each needs corroboration before it costs anyone their enquiry.

The one exception is the hidden field, weighted at 55 so it flags alone. A field that is not rendered cannot be filled in by a person, and the commonest spam bot fills every field it can find and trips nothing else.

That check needs the Form Guard field on the form, because the field is what renders the hidden input. On a form without it the check abstains and says so in the breakdown. If spam is getting through on one form and not another, this is the first thing to check.

The three outcomes

Every check returns one of three things, and the difference between the last two matters:

Outcome Points Meaning
Fired > 0 The check found what it looks for.
Clear 0 The check ran and found nothing.
Abstained 0 The check could not reach a conclusion.

An abstention is recorded, not hidden. "The blocklist was unreachable" and "the blocklist said they were fine" are very different answers to give a client, and the entry breakdown distinguishes them.

Abstentions never add points. A check that cannot answer does not get a vote.

Reading a breakdown

Open any entry. The Form Guard panel shows:

  • the total score and the threshold it was measured against
  • every check that contributed, with its points and a specific explanation ("7 links found; this form allows 4")
  • every check that could not run, and why

This is the answer to "why did we never get that enquiry?" — and it is the reason to prefer this over a filter that only gives you a verdict.

If real enquiries are being filtered

Work down this list in order.

  1. Open the entry and read the breakdown. It names the checks that fired. Fix the cause rather than raising the threshold.
  2. Wrong domain flagged? Add it under Always accept these domains. Do this the moment it happens once; it never expires.
  3. A whole office being caught? They share one outward address. Raise Submissions allowed per address.
  4. Slow, considered forms being caught on speed? Lower Minimum seconds to complete, or set it to zero to switch it off.
  5. Only as a last resort, raise the flag threshold. It is the blunt instrument: it weakens every check at once, including the ones that were right.

If spam is getting through

  1. Look at what the breakdown scored. If the total was 30 against a threshold of 50, you need one more signal, not a lower threshold.
  2. Turn on the external blocklist if your client's privacy position allows it (read Privacy first — it is the only check that transmits anything).
  3. Raise the weight of whatever consistently fires on the spam you are receiving.
  4. Lower the flag threshold to 40. Then watch the weekly digest for a fortnight before going lower.

The weekly digest

Filtering is silent by design, which means a mistake is silent too. The weekly digest lists what was filtered and why, so a false positive is something you notice rather than something a client eventually mentions.

It reports a summary, not the messages themselves. Emailing the full contents of suspected spam to a client's inbox would undo the point of filtering it.

Leave it on.

Refusing submissions outright

Off by default, and worth leaving off.

A refused submission leaves no record at all. If a real customer is ever caught by it, neither you nor your client will ever know it happened. A filed one sits in the Spam folder and can be restored in a click.

Filing already achieves the goal — Gravity Forms suppresses notifications for spam entries, so the client stops receiving it either way. Refusing also hands a spammer a tuning oracle: they learn immediately which payload changes get through, while a filed submission looks to them like success.

If you do switch it on, the refuse threshold cannot be set below the flag threshold, and no pushed policy can ever enable it. That stays a local decision made by someone looking at that specific site.

Fleet policy

Sites pull a signed policy from plugins.ajcomputers.com twice a day, so thresholds can be tuned once across every site you manage.

Four things bound what a policy can do:

  1. Signed with the same Ed25519 keys as the update channel.
  2. Clamped — every value is forced into a range hardcoded in the plugin. A threshold of zero is impossible however it was signed.
  3. Limited — only thresholds, weights and tuning are settable. Refusing submissions and every provider credential are unreachable from a policy.
  4. Refusable — any site can opt out permanently.

To opt one site out, in wp-config.php:

define( 'AJC_FORM_GUARD_NO_POLICY', true );

It lives outside the database, so it survives a restore from a backup taken before the exception was needed.

To publish a policy:

bin/sign-policy.sh policy.json

The script validates the document against the same bounds the plugin enforces and refuses to sign anything that would be clamped or ignored — so a mistake is caught on your workstation rather than becoming a silent behaviour change on forty sites. Upload policy.json and policy.json.sig together.

{
  "settings": {
    "flag_threshold": 45,
    "cadence_limit": 8,
    "weights": { "link_count": 25 }
  },
  "domains_add": [ "newthrowaway.test" ],
  "domains_remove": [ "wrongly-listed.example" ]
}

Retention

Filed spam is deleted after 30 days by default.

Only entries this plugin filed are ever removed. Anything Akismet, the Gravity Forms honeypot, or a person marked as spam is left alone — deleting those would be destroying data on someone else's judgement.

Questions about AJC Form Guard?

Talk to the people who build and support it.