[object Object]

← back to Thesetdecorator

TSD a11y: add autocomplete to personal-identity form fields (WCAG 1.3.5, DTD verdict A)

818a6517244c7558944ebce90800feb7418932f9 · 2026-06-03 12:39:36 -0700 · Steve

Conservative scope — tagged 11 unambiguous personal-identity inputs across
submit/job-board/decorator (email->email, tel->tel, name->name, website->url,
agency->organization). Deliberately skipped ambiguous/context fields
(display_name, shared_folder_url, job metadata, verify/linkedin/headshot URLs,
bio) where a wrong token degrades autofill UX — risk I can't verify
autonomously. Idempotent scripts/form-autocomplete.py; verified correct tokens,
well-formed tags, ambiguous fields untouched. Invisible. Static — queued deploy.

Files touched

Diff

commit 818a6517244c7558944ebce90800feb7418932f9
Author: Steve <steve@designerwallcoverings.com>
Date:   Wed Jun 3 12:39:36 2026 -0700

    TSD a11y: add autocomplete to personal-identity form fields (WCAG 1.3.5, DTD verdict A)
    
    Conservative scope — tagged 11 unambiguous personal-identity inputs across
    submit/job-board/decorator (email->email, tel->tel, name->name, website->url,
    agency->organization). Deliberately skipped ambiguous/context fields
    (display_name, shared_folder_url, job metadata, verify/linkedin/headshot URLs,
    bio) where a wrong token degrades autofill UX — risk I can't verify
    autonomously. Idempotent scripts/form-autocomplete.py; verified correct tokens,
    well-formed tags, ambiguous fields untouched. Invisible. Static — queued deploy.
---
 public/decorator.html        | 10 +++----
 public/job-board.html        |  6 ++--
 public/submit.html           |  6 ++--
 scripts/form-autocomplete.py | 65 ++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 76 insertions(+), 11 deletions(-)

diff --git a/public/decorator.html b/public/decorator.html
index d8a817d..dd119ae 100644
--- a/public/decorator.html
+++ b/public/decorator.html
@@ -58,8 +58,8 @@
     <form method="dialog">
       <h2 style="margin-top:0">Claim this profile</h2>
       <p class="muted" style="font-size:0.9rem">We'll verify you're <strong id="claim-target-name"></strong> by checking the link you provide against the IMDb entry. Once verified, your bio, city, agency, contact, headshot, and additional credits replace the placeholder fields here.</p>
-      <p><label>Your name<br><input id="claim-name" type="text" required style="width:100%"></label></p>
-      <p><label>Your email (where verification confirmation goes)<br><input id="claim-email" type="email" required style="width:100%"></label></p>
+      <p><label>Your name<br><input id="claim-name" type="text" required style="width:100%" autocomplete="name"></label></p>
+      <p><label>Your email (where verification confirmation goes)<br><input id="claim-email" type="email" required style="width:100%" autocomplete="email"></label></p>
       <p><label>Verification link — IMDb / agency / SDSA profile that proves this is you<br><input id="claim-verify" type="url" required style="width:100%" placeholder="https://www.imdb.com/name/nm…"></label></p>
       <hr>
       <p><label>City<br>
@@ -73,10 +73,10 @@
           <option>Other</option>
         </select>
       </label></p>
-      <p><label>Agency or representation<br><input id="claim-agency" type="text" style="width:100%" placeholder="e.g. UTA · Gersh · Verve"></label></p>
+      <p><label>Agency or representation<br><input id="claim-agency" type="text" style="width:100%" placeholder="e.g. UTA · Gersh · Verve" autocomplete="organization"></label></p>
       <p><label>Public LinkedIn URL (optional)<br><input id="claim-linkedin" type="url" style="width:100%"></label></p>
-      <p><label>Public phone (optional, shown on profile)<br><input id="claim-phone" type="tel" style="width:100%"></label></p>
-      <p><label>Public email (optional, shown on profile)<br><input id="claim-pubemail" type="email" style="width:100%"></label></p>
+      <p><label>Public phone (optional, shown on profile)<br><input id="claim-phone" type="tel" style="width:100%" autocomplete="tel"></label></p>
+      <p><label>Public email (optional, shown on profile)<br><input id="claim-pubemail" type="email" style="width:100%" autocomplete="email"></label></p>
       <p><label>Headshot URL (optional)<br><input id="claim-headshot" type="url" style="width:100%"></label></p>
       <p><label>Short bio (optional, 1-3 sentences)<br><textarea id="claim-bio" rows="3" style="width:100%"></textarea></label></p>
       <div style="display:flex;gap:0.5rem;justify-content:flex-end;margin-top:1rem">
diff --git a/public/job-board.html b/public/job-board.html
index f6ef4ab..dd6b00e 100644
--- a/public/job-board.html
+++ b/public/job-board.html
@@ -132,10 +132,10 @@
                 <option>union hall</option>
               </select>
             </label></p>
-            <p><label>Contact value<br><input id="j-contact" type="text" required placeholder="email / phone / agency name" maxlength="200"></label></p>
+            <p><label>Contact value<br><input id="j-contact" type="text" required placeholder="email / phone / agency name" maxlength="200" autocomplete="name"></label></p>
             <hr style="grid-column:1/-1;border:none;border-top:1px solid var(--rule);margin:0.5rem 0">
-            <p><label>Your name<br><input id="j-sname" type="text" required maxlength="80"></label></p>
-            <p><label>Your email<br><input id="j-semail" type="email" required maxlength="120"></label></p>
+            <p><label>Your name<br><input id="j-sname" type="text" required maxlength="80" autocomplete="name"></label></p>
+            <p><label>Your email<br><input id="j-semail" type="email" required maxlength="120" autocomplete="email"></label></p>
             <p style="grid-column:1/-1"><label>Your union/role (optional)<br><input id="j-sunion" type="text" placeholder="e.g. IATSE Local 800 / Production Designer" maxlength="60"></label></p>
           </div>
           <p style="display:flex;gap:0.5rem;align-items:center;margin-top:1rem"><button class="btn primary" type="submit">Submit for moderation</button> <span id="j-status" class="muted" style="font-size:0.85rem"></span></p>
diff --git a/public/submit.html b/public/submit.html
index 051ba19..f319106 100644
--- a/public/submit.html
+++ b/public/submit.html
@@ -101,7 +101,7 @@
       <div class="row">
         <div>
           <label>Your Google email (the one that owns the Drive folder)</label>
-          <input type="email" name="email" required placeholder="you@gmail.com">
+          <input type="email" name="email" required placeholder="you@gmail.com" autocomplete="email">
         </div>
         <div>
           <label>Display name on the card (optional)</label>
@@ -115,11 +115,11 @@
       <div class="row">
         <div>
           <label>Website / portfolio (optional)</label>
-          <input type="url" name="website" placeholder="https://yourportfolio.com">
+          <input type="url" name="website" placeholder="https://yourportfolio.com" autocomplete="url">
         </div>
         <div>
           <label>Real name (for tax records — never public)</label>
-          <input type="text" name="real_name" placeholder="Steve Photographer">
+          <input type="text" name="real_name" placeholder="Steve Photographer" autocomplete="name">
         </div>
       </div>
       <div>
diff --git a/scripts/form-autocomplete.py b/scripts/form-autocomplete.py
new file mode 100644
index 0000000..02e6085
--- /dev/null
+++ b/scripts/form-autocomplete.py
@@ -0,0 +1,65 @@
+#!/usr/bin/env python3
+"""Idempotent: add autocomplete to unambiguous personal-identity form fields
+(WCAG 1.3.5 Identify Input Purpose, DTD verdict A — conservative scope).
+
+Tokens are added ONLY to fields that unambiguously collect the user's own
+identity/contact data, where the token is mechanically certain. Ambiguous /
+context-dependent fields (display_name, shared_folder_url, job metadata,
+verify/linkedin/headshot URLs, bio) are deliberately left untouched — a wrong
+token degrades UX via incorrect autofill, and autofill can't be verified in an
+autonomous run. Invisible change (attribute only).
+
+Matching is by the input's id= or name= (whichever the page uses). Idempotent:
+skips an input that already has autocomplete. Reversible.
+    python3 scripts/form-autocomplete.py
+"""
+import os, re
+
+PUB = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "public")
+
+# file -> { id_or_name : token }   (conservative, unambiguous personal-identity fields only)
+PLAN = {
+    "submit.html": {
+        "email": "email", "website": "url", "real_name": "name",
+    },
+    "job-board.html": {
+        "j-contact": "name", "j-sname": "name", "j-semail": "email",
+    },
+    "decorator.html": {
+        "claim-name": "name", "claim-email": "email", "claim-agency": "organization",
+        "claim-phone": "tel", "claim-pubemail": "email",
+    },
+}
+
+def add_token(html, key, token):
+    """Add autocomplete=token to the <input> whose id= OR name= equals key,
+    if it doesn't already have an autocomplete attr. Returns (html, changed)."""
+    # match a single <input ...> tag that contains id="key" or name="key"
+    pat = re.compile(r'<input\b(?=[^>]*\b(?:id|name)=["\']' + re.escape(key) + r'["\'])[^>]*>', re.IGNORECASE)
+    m = pat.search(html)
+    if not m:
+        return html, "absent"
+    tag = m.group(0)
+    if re.search(r'\bautocomplete=', tag, re.IGNORECASE):
+        return html, "already"
+    newtag = tag[:-1].rstrip() + f' autocomplete="{token}">'
+    return html[:m.start()] + newtag + html[m.end():], "changed"
+
+total_changed, report = 0, []
+for fname, fields in PLAN.items():
+    path = os.path.join(PUB, fname)
+    if not os.path.exists(path):
+        report.append(f"{fname}: MISSING FILE"); continue
+    html = open(path, encoding="utf-8").read()
+    per = []
+    for key, token in fields.items():
+        html, status = add_token(html, key, token)
+        per.append(f"{key}->{token}:{status}")
+        if status == "changed":
+            total_changed += 1
+    open(path, "w", encoding="utf-8").write(html)
+    report.append(f"{fname}: " + ", ".join(per))
+
+print(f"total inputs tagged: {total_changed}")
+for r in report:
+    print("  " + r)

← 443a9c7 TSD SEO: backfill og:site_name on 23 pages with OG blocks bu  ·  back to Thesetdecorator  ·  backlog: loop #10 (og:site_name + WCAG autocomplete) + deplo c738710 →