Skip to content

Say when a seal can never be checked, instead of "try again" - #42

Merged
threeqube merged 1 commit into
mainfrom
seal-uncomputable
Nov 4, 2026
Merged

threeqube merged 1 commit into
mainfrom
seal-uncomputable

Conversation

@threeqube

@threeqube threeqube commented Nov 3, 2026 •

Copy link
Copy Markdown
Collaborator

Closes #40.

What changes

When verifier-core can't compute a credential's seal for a reason that won't go away, verifier-plugin now says so instead of "We couldn't check this right now… Try again in a little while."

The signature check reports Before After
PARSING_ERROR: a field the credential's @context doesn't define ("Safe mode validation error") ⚪ We couldn't check this right now. Something went wrong while we were checking… Try again in a little while. ⚪ We can't check this credential. It contains something we don't recognise, so we can't tell whether it's genuine. This is usually a problem with how it was made. Ask the issuer for a replacement. (signature_unreadable)
PROOF_UNSUPPORTED: no seal of a kind verifier-core can check, or one made for another purpose ⚪ the same ⚪ We can't check this credential. It has a kind of digital signature we can't check, so we can't tell whether it's genuine. Let the issuer know. (signature_unsupported)
  • Both are grey. Red was tried first. It breaks the consistency suite's rule that a red verdict needs a red row, and every row here honestly reads "not checked". The rows don't change.
  • unreadable_vocabulary (the same cause caught before the seal, red) gets the first message's words: same cause, same words. verifier-core 2.0.0-beta.1 never reaches it, so no one sees the change today.
  • A seal we can't compute says "try again later", and lets a forgery soften its warning #40's forgery: the demo's "Changed" credential plus one made-up field went from grey "try again" to the new grey message. It isn't red "tampered", because we genuinely can't tell, but it no longer blames a glitch.
  • Unchanged:
    • An unreachable issuer website still says "try again", and wins when both are reported.
    • A seal that doesn't match still says "tampered", even beside one that can't be computed.
    • One good seal beside an unsupported one still passes.

Wording, for feedback

  • "Can't check", not "can't read" (the old early-catch headline). The card shows the credential's title, so we plainly did read it.
  • "Something we don't recognise", not "vocabulary we couldn't process". Plain words.
  • "Usually a problem with how it was made" leaves room for a forgery without accusing anyone.
  • "Let the issuer know", not "ask for a replacement", for an unsupported seal. A new copy would most likely carry the same kind of seal.
  • No "yet", which would promise support nobody has planned.
  • One loose fit: PROOF_UNSUPPORTED also covers a seal made for another purpose (e.g. authentication). "A kind of digital signature we can't check" is slightly loose there, but the advice is still right. I didn't add a third message for it.

Checks

Expected results were written before the change.

  • Unit tests: lint, typecheck, and 156,425 tests, about 13 s locally (main has 105,720; the consistency suite now covers the two new seal results).

    • Pinned to the real library: two tests in problem-types.test.ts run verifier-core itself, so a rename of either problem type fails here.
    • The consistency suite now requires these two seal results to reach their own message and never say "try again".
  • Deliberate mistakes: each fails tests.

    Mistake Tests failing
    Drop either new branch about 21,100
    Make the new message red 21,122
    Put "try again" back 21,122
    Let the dictionary problem outrank a website outage 2
  • Side by side: main's build, byte-identical to its published release build 5622f4d, against this branch's, on 1,763 credentials. Those are Take the patched dev tools in #37: vite, undici, shell-quote, source-map-js #39's 1,711 altered ones plus ECDSA, did:web and handmade cases, each run with and without registry lookups.

  • Edge cases, against the real library: a seal made for another purpose; two seals, both unsupported; a good seal plus an unsupported one; a tampered seal plus an unsupported one; a tampered seal plus one that can't be computed. Each gives the result above.

  • Browser: in Chromium and WebKit, the demo's 12 buttons and 9 vc-test-fixtures links are identical to the live demo (66 comparisons). A seal we can't compute says "try again later", and lets a forgery soften its warning #40's example shows the new message.

  • Independent review: no correctness bugs. Its test gaps are closed above.

  • Test files type-checked (CI doesn't): the same 28 errors as main, none new.

  • Smoke test, live demo against this PR's preview. Expected: 0 of 21 differ. No demo button or link reaches these cases.
    Result: 0 of 21 differ, in Chromium and WebKit, two rounds each. The preview is 06a762c (main 94675b0 + 930f686). A seal we can't compute says "try again later", and lets a forgery soften its warning #40's example on the preview (the live demo's tampered credential plus "notInAnyContext": "x", opened with ?vc=) shows "Couldn't check: We can't check this credential" where the live demo shows "We couldn't check this right now"; the tampered credential alone is red "tampered" on both. CI passed: unit and browser tests, build, publish, and the tests against the published preview.

Not in this PR

Reaching the wallet

Through the next verifier-plugin pin bump, with #31, #33 and #38.

🤖 Generated with Claude Code

When verifier-core can't compute a seal because a field isn't defined by the
credential's vocabulary (PARSING_ERROR), or the seal is of a kind it can't
check (PROOF_UNSUPPORTED), the answer is the same every time. Both fell
through to "We couldn't check this right now... Try again", which also let a
forger turn red "tampered" grey with one made-up field.

They now get signature_unreadable and signature_unsupported: grey, since every
row beneath reads "not checked", with words that send the person to the
issuer. unreadable_vocabulary shares the first's words. The consistency suite
covers both seal results, and real-library tests pin the two problem types.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Nov 3, 2026

Copy link
Copy Markdown
Contributor

Try it: https://digitalcredentials.github.io/verifier-plugin/pr-42/

Updates on every push to this PR, and goes away when it closes. The browser tests run against this copy too.

@threeqube

Copy link
Copy Markdown
Collaborator Author

Smoke test and merge confidence

Smoke test: live demo (94675b0) against this PR's preview (06a762c)

  • By hand, in Chrome:

    • Both version.txt files are correct.
    • All 12 demo buttons show the expected headline, and the two sites match each other, rows included.
    • Changed is still red "tampered" on the preview.
  • Automated: 0 of 21 differ (the 12 buttons and 9 vc-test-fixtures links), in Chromium and WebKit, two rounds each.

  • A seal we can't compute says "try again later", and lets a forgery soften its warning #40's example: the demo's tampered credential plus "notInAnyContext": "x". It's now run in WebKit as well as Chromium, with the same result in both:

    Live demo Preview
    Tampered credential 🔴 This credential has been tampered with 🔴 This credential has been tampered with
    Plus one made-up field ⚪ We couldn't check this right now… Try again in a little while. ⚪ We can't check this credential. It contains something we don't recognise… Ask the issuer for a replacement.

    The test harness hands this credential to the page at a made-up address; everything else is the deployed site. This PR doesn't change how credentials are fetched, and the 9 links cover real fetching.

Merge confidence: high

  • It merges exactly what was tested.
    • Main is still 94675b0, the base for the preview, CI and every smoke test.
    • There are no conflicts, and all 5 checks pass.
  • Only the intended change. Of 1,763 credentials compared side by side, 303 moved to the two new messages. Nothing else changed, in any row or output.
  • The tests guard it:
    • 156,425 tests pass.
    • All 5 deliberate mistakes are caught.
    • Two tests run the real verifier-core, so if verifier-core renames either problem type, they fail here.
  • The independent review found no correctness bugs.
  • If a case was missed, an unforeseen failure falls through to the existing "We couldn't check this right now", which is today's behaviour.
  • Reach:
    • The live demo updates on merge.
    • The wallet is unaffected until its verifier-plugin pin is bumped, and that bump gets its own wallet test.
    • A merge commit is a one-click revert.

Open, not blocking

@threeqube
threeqube merged commit 72683b8 into main Nov 4, 2026
6 checks passed
@threeqube
threeqube deleted the seal-uncomputable branch November 4, 2026 17:54
github-actions Bot added a commit that referenced this pull request Nov 4, 2026
@threeqube

Copy link
Copy Markdown
Collaborator Author

After merge (4 November 2026)

#40 closed. The live demo serves the merge 72683b8, whose code is identical to the preview tested above (06a762c): the two commits have the same tree. CI on main passed, as did the release and preview jobs.

Post-merge smoke test

Expectations were written before running.

Check Expected Result
Live demo against the preview's recorded results. The 12 demo buttons and 9 vc-test-fixtures links, every line on screen compared with what pr-42's preview showed, in Chromium and WebKit, 2 rounds each. 0 differ 0 of 66 page loads differ in each engine
#40's example on the live demo. The tampered credential plus "notInAnyContext": "x", in Chromium and WebKit. Grey "We can't check this credential… Ask the issuer for a replacement." As expected in both
The tampered credential alone, on the live demo, in both engines Red "This credential has been tampered with" As expected in both
What the wallet will get. The release branch's dist/ (ccb0381) compared with dist/ built locally from 72683b8. Byte-identical Byte-identical

The wallet picks this up at its next verifier-plugin pin bump.

@threeqube

Copy link
Copy Markdown
Collaborator Author

In the wallet: lcw-sandbox.org (9 November 2026)

All clear. This PR has now reached the wallet. James deployed lcw-sandbox.org with lcw-front-end 0034b08, which pins release at a2a2181, the build of main 7c57591. That build includes #31, #33, #38, #39, #41, #42 and #43. I wrote the expectations down before checking.

  • Right build: a2a2181's dist/ is byte-identical to a fresh build of 7c57591, and its wording is in the live wallet's JavaScript.
  • Same behaviour as main: I gave the deployed <verifier-credential> on lcw-sandbox.org and the live demo (also 7c57591) the same 107 credentials and the same registries: the 12 demo situations, 4 built for No status behind a seal that didn't hold #33 and Say when a seal can never be checked, instead of "try again" #42, and the 91 in vc-test-fixtures. All 107 gave the same verdict, severity and card text.
  • Signed in to the wallet (the deployed smoke test's demo account, read only): the LCW Experience Badge reads "Verified", with the issuer "a known issuer" and Tampering "none detected", at desktop and phone widths. The card logs no console errors of its own. The only errors are the known ones: the OpenID Federation registries block browser requests.
What this PR changed In the wallet
A kind of seal we can't check ✅ grey "We can't check this credential. It has a kind of digital signature we can't check… Let the issuer know."
A field the vocabulary doesn't define ✅ grey "We can't check this credential. It contains something we don't recognise… Ask the issuer for a replacement."
Old wording gone ✅ "We can't read this credential" is no longer in the live JavaScript

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

A seal we can't compute says "try again later", and lets a forgery soften its warning

1 participant