I maintain two Magento modules that must agree with each other. angeo/module-ucp writes a store’s UCP profile. angeo/module-aeo-audit checks it. For six weeks they did not agree. The audit told store owners that a correct profile had no signing keys.
I found it on 16 October 2026, while reviewing the audit for a release. This post explains what happened, why my tests did not catch it, and what I changed.
The timeline
| Date | What happened |
|---|---|
| UCP release 2026-08-25 | The Universal Commerce Protocol publishes a new dated release. Signing keys move from signing_keys[] to keys[]. |
| 1 Sep 2026 | module-ucp 2.0.0 adopts the new release. Profiles now say "version": "2026-08-25" and publish keys in keys[]. |
| 11 Sep 2026 | module-aeo-audit 4.2.0 ships. Its UCP checker still knows 2026-04-08 as the newest release and reads only signing_keys. |
| 15 Oct 2026 | module-aeo-audit 4.2.4 ships. Same checker. |
| 16 Oct 2026 | Found in review. Fixed in module-aeo-audit 4.3.0. |
What the audit said
A store with module-ucp 2.x and keys set up got a warning with two problems:
UCP protocol version "2026-08-25" is not one this audit knows
(2026-04-08, 2026-01-11, 2026-01-23) — it may be newer than this release
No signing_keys declared — RFC 9421 HTTP Message Signatures will not validate
The UCP signal has a weight of 0.9. A warning counts half. So a correct profile lost points in every audit.
The first message was fine. It was honest: “this version may be newer than me”. The second message was the real problem. It told the store owner the opposite of the truth. The keys were there. They were in a field the checker did not read.
What changed in the spec
The 2026-08-25 release notes list it as a breaking change: signing_keys[] was removed from the profile, and keys[], a JWK Set, is now the only canonical field for signing keys.
Before, a profile looked like this:
{
"ucp": { "version": "2026-04-08", "services": { … } },
"signing_keys": [ { "kty": "EC", "crv": "P-256", "kid": "k1", … } ]
}
Now it looks like this:
{
"ucp": { "version": "2026-08-25", "services": { … } },
"keys": [ { "kty": "EC", "crv": "P-256", "kid": "k1", … } ]
}
A verifier that follows the new release reads only keys[]. So module-ucp had to move. The audit had to move too, and it did not.
Why my tests stayed green
The audit has unit tests for the UCP checker. Every test fixture used version 2026-04-08 and signing_keys. The tests proved that the code matched my idea of the spec. They could not tell me that the spec had changed.
I had seen this risk before. In August I removed a schema-validation job from the UCP modules for the same reason: its spec tag was pinned by hand, so it could never notice a new release.
The fix
module-aeo-audit 4.3.0 does four things:
- 2026-08-25 is the current release. 2026-04-08 moves to the list of older releases, so a profile on it gets “you are behind”, not “unknown version”.
- The checker reads
keys[]first and falls back tosigning_keys[]. Older profiles still validate. - A profile that says 2026-08-25 but still uses
signing_keys[]gets a clear warning: since 2026-08-25 the field iskeys[]. - New tests cover both shapes. The old fixtures now use the new release.
foreach (['keys', 'signing_keys'] as $field) {
$candidate = $profile[$field] ?? ($ucp[$field] ?? null);
if (is_array($candidate) && isset($candidate['keys'])) {
$candidate = $candidate['keys']; // a JWK Set object {"keys": [...]}
}
if (is_array($candidate) && $candidate !== []) {
$keysField = $field;
$signingKeys = array_values($candidate);
break;
}
}
What I take from it
- A renamed field is worse than a new version number. An unknown version can say “I don’t know this”. A missing field looks like “absent”, and the check reports a false problem. When a field is missing, check whether the spec renamed it before you report it.
- Unit tests freeze your reading of the spec. They are still worth having. But they need a second source of truth next to them.
- Two modules that must agree need a shared test. The next step is a contract test: generate a profile with module-ucp and run the audit checker on it in CI. I have not built it yet. It is now on the list.
- Degrade to a warning, not a failure. The checker treated the unknown version as a warning. That limited the damage. A hard failure would have been worse.
If you ran the audit between September and October
If your store uses module-ucp 2.x and module-aeo-audit 4.0 to 4.2.x showed “No signing_keys declared”, ignore that line. Check your profile directly:
curl -s https://your-store/.well-known/ucp | jq '{version: .ucp.version, keys: (.keys | length)}'
If keys is 1 or more, your keys are published. Then update the audit to 4.3.0.