← back to Dw Signup Fulfillment
document TK-11114 signup email failure proof
5083a8770bece9ecede35da15d107f77bf7a2329 · 2026-09-02 10:32:38 -0700 · Steve Abrams
Files touched
A verification/tk11114/A2A-HANDOFF.mdA verification/tk11114/E2E-PROOF.mdA verification/tk11114/ROLLBACK-MAP.mdA verification/tk11114/before-customers-count.jsonA verification/tk11114/before-endpoint-badtoken.jsonA verification/tk11114/before-endpoint-realtoken-emptybody.jsonA verification/tk11114/before-endpoint-registeredtoken-emptybody.jsonA verification/tk11114/before-git-head.txtA verification/tk11114/before-git-status.txtA verification/tk11114/before-health.jsonA verification/tk11114/before-scopes.jsonA verification/tk11114/before-webhooks.jsonA verification/tk11114/e2e-proof.jsonA verification/tk11114/rollback-delete.jsonA verification/tk11114/rollback-verify.jsonA verification/tk11114/test-customer-create.jsonA verification/tk11114/test-customer.jsonA verification/tk11114/trigger-1.json
Diff
commit 5083a8770bece9ecede35da15d107f77bf7a2329
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Wed Sep 2 10:32:38 2026 -0700
document TK-11114 signup email failure proof
---
verification/tk11114/A2A-HANDOFF.md | 21 +++++++++++
verification/tk11114/E2E-PROOF.md | 30 +++++++++++++++
verification/tk11114/ROLLBACK-MAP.md | 30 +++++++++++++++
verification/tk11114/before-customers-count.json | 1 +
verification/tk11114/before-endpoint-badtoken.json | 1 +
.../before-endpoint-realtoken-emptybody.json | 1 +
.../before-endpoint-registeredtoken-emptybody.json | 1 +
verification/tk11114/before-git-head.txt | 1 +
verification/tk11114/before-git-status.txt | 2 +
verification/tk11114/before-health.json | 1 +
verification/tk11114/before-scopes.json | 1 +
verification/tk11114/before-webhooks.json | 1 +
verification/tk11114/e2e-proof.json | 43 ++++++++++++++++++++++
verification/tk11114/rollback-delete.json | 1 +
verification/tk11114/rollback-verify.json | 1 +
verification/tk11114/test-customer-create.json | 1 +
verification/tk11114/test-customer.json | 6 +++
verification/tk11114/trigger-1.json | 1 +
18 files changed, 144 insertions(+)
diff --git a/verification/tk11114/A2A-HANDOFF.md b/verification/tk11114/A2A-HANDOFF.md
new file mode 100644
index 0000000..91fb101
--- /dev/null
+++ b/verification/tk11114/A2A-HANDOFF.md
@@ -0,0 +1,21 @@
+# TK-11114 — A2A Handoff (iterm-tk11114-webhook → /root)
+
+**Status: PARTIAL / BLOCKED** · delegation_chain `/root → iterm-tk11114-webhook` (depth 1) · gates preserved.
+
+## What I did (all within approved scope)
+- Read `a2a-contract` + `e2e-proof` SKILL.md fully. Took R4 before-snapshots (read-only) → `verification/tk11114/`.
+- **Discovered the premise was false** (webhook already present + wired since 2026-08-06) → **did NOT register** (would duplicate → double emails) and **did NOT touch env/pm2** (running token present + matches). No mutation on Actions #1/#2.
+- Ran the pre-approved **Action #3** controlled test: created ONE test customer via the real signup path (Steve-owned `+dwgolive` alias), confirmed the webhook handler fires, and found the **send fails**.
+- **Rolled back**: deleted the test customer (DELETE 200 → GET 404). No webhook/env to revert.
+
+## Changed paths / commits
+- Added: `verification/tk11114/` (snapshots, ROLLBACK-MAP.md, E2E-PROOF.md, e2e-proof.json, this handoff). **No commit made** (per finalizer: do not sweep unrelated untracked files). `send-kelly-reply.js` + other untracked files untouched.
+
+## Exact root cause (the real broken thing)
+DW signup verify-email is broken at the **send side**, not the webhook: `dw-signup-fulfillment → George /api/send` fails for **100% of signups** (0 successes ever), and the error is **swallowed** (`lib/verify.js#startVerification` drops the reason; `lib/email.js#georgePost` logs nothing on failure). Real customer `jolainajones@me.com` is currently affected. = systemic cause of Kelly's report (TK-10830).
+
+## Residual risk / skipped
+- Verify-click→tag and happy-path idempotency are **unproven** (send never succeeds). Exact George-auth fault is the prime suspect (`config.GEORGE_ENVS` precedence on Kamatera) but **UNCONFIRMED** — stopped per finalizer.
+
+## Approvals still required / safest next action (GATED)
+Fix is OUTSIDE this task's webhook scope + is a prod service→George integration change → drafted to `~/.claude/yolo-queue/pending-approval/tk11114-dw-signup-george-send-broken-2026-09-02.md`. Two parts: (1) repair the service→George auth resolution; (2) add a real failure log so a swallowed send never hides again. Recommend routing to the service owner (vp-dw-commerce / golive-steward).
diff --git a/verification/tk11114/E2E-PROOF.md b/verification/tk11114/E2E-PROOF.md
new file mode 100644
index 0000000..60b30f7
--- /dev/null
+++ b/verification/tk11114/E2E-PROOF.md
@@ -0,0 +1,30 @@
+# TK-11114 — E2E Proof (R4) · Status: PARTIAL / BLOCKED
+
+**Agent:** iterm-tk11114-webhook → **Finalizer:** /root · **2026-09-02** · git HEAD `ce79cb4`
+**Store:** designer-laboratory-sandbox.myshopify.com (LIVE prod) · **Service:** dw-signup-fulfillment (Kamatera :9862, dry_run=false)
+
+## Headline
+The task premise was **false**, and the real defect is elsewhere:
+- **The `customers/create` webhook was NOT missing.** It has existed since **2026-08-06** (id `1490453430323`) and is **correctly wired** (running `WEBHOOK_URL_TOKEN` matches the registered address). ⇒ **Actions #1 (register) and #2 (env/pm2 restart) were NOT fired** — registering a second one would have caused **duplicate/double emails**.
+- **The DW signup verify-email is broken at the SEND side.** Every `customers/create` fires the handler correctly, but the George send **fails for 100% of signups** (0 successful sends in the last 1500 prod log lines), and the error is **swallowed**. A real customer (`jolainajones@me.com`) is affected right now. **This is the true root cause of Kelly's missing-email report (TK-10830) — not a missing webhook.**
+
+## Checks
+| Boundary | Assertion | Verdict |
+|---|---|---|
+| shopify webhook registry | customers/create exists + wired | **PASS** (registered-token probe → 200 received) |
+| service env | running `WEBHOOK_URL_TOKEN` present + matches | **PASS** (bad→401, registered→200) — #2 unneeded |
+| webhookAuth (negative) | invalid token rejected | **PASS** (401 `bad_webhook_token`) |
+| customer create (real path) | 1 controlled test customer, Steve `+dwgolive` alias | **PASS** (201, id `8412197617715`) |
+| handler fires | customers/create reaches handler + re-fetch | **PASS** (prod log `[webhook] customers/create id=8412197617715`) |
+| **email send (George) — critical** | verify letter delivered to controlled mailbox | **FAIL** (`started.ok:false`; `verify letter NOT sent`; 0 sends ever; inbox empty) |
+| verify click → `verified-sample` tag | tag on click | **SKIP** (no email/link ever issued — critical SKIP) |
+| duplicate-delivery idempotency | 2nd delivery = no-op | **INCONCLUSIVE** (failed-send branch leaves the flag unset by design) |
+| cleanup / rollback | test customer removed | **PASS** (DELETE 200 → GET 404) |
+
+A critical-path FAIL + SKIP ⇒ **no `done`/`fixed` claim**. Reported PARTIAL/BLOCKED.
+
+## Root cause (for the fix, out of THIS task's scope)
+`dw-signup-fulfillment` → George `/api/send` fails on every signup; `lib/verify.js#startVerification` returns `ok:false` **with no reason**, and `lib/email.js#georgePost` **logs nothing on failure**, so the outage is invisible. George itself answers a *direct* `/api/send` with 200 — but per finalizer that manual probe does **not** prove the organic service→George path (which is 0/0). Prime suspect: `config.GEORGE_ENVS` credential/token resolution precedence on Kamatera (`~/Projects/george-gmail/.env` is checked **before** the correct `~/DW-Agents/gmail-agent/.env`) — **UNCONFIRMED** (stopped per finalizer). Fix = repair the service→George auth resolution **and** add a real failure log so a swallowed send never hides again. Gated → drafted to pending-approval.
+
+## Rollback executed
+Test customer `8412197617715` DELETE → 200, GET → 404. **No webhook registered, no env changed, no pm2 restart** → nothing else to revert. Token redacted from all evidence (scan clean). `send-kelly-reply.js` and other untracked files left untouched.
diff --git a/verification/tk11114/ROLLBACK-MAP.md b/verification/tk11114/ROLLBACK-MAP.md
new file mode 100644
index 0000000..5aa9d25
--- /dev/null
+++ b/verification/tk11114/ROLLBACK-MAP.md
@@ -0,0 +1,30 @@
+# TK-11114 — Rollback Map (written BEFORE any mutation)
+
+**Agent:** iterm-tk11114-webhook · **Finalizer:** /root · **Written:** 2026-09-02 (pre-mutation)
+**Store:** designer-laboratory-sandbox.myshopify.com (LIVE prod; legacy misnomer) · Admin API 2024-10
+**Service:** dw-signup-fulfillment (Kamatera pm2, PORT 9862, PUBLIC https://signup.designerwallcoverings.com), dry_run=false
+
+## Corrected premise (verified read-only, see snapshots)
+The task premise ("0 webhooks; customers/create MISSING; restore it") is **FALSE as of 2026-09-02T17:13Z**:
+- A `customers/create` webhook **already exists**, id **1490453430323**, created **2026-08-06T16:24:15-07:00**,
+ address `https://signup.designerwallcoverings.com/webhooks/customers/create/[REDACTED-last4:e9c9]`.
+- An `orders/paid` webhook also exists (id 1499222474803, created 2026-08-28).
+- The running service's `WEBHOOK_URL_TOKEN` **matches** the registered webhook (probe with the registered-address token → 200 `{ok:true,received:true}`; bad token → 401).
+- Therefore **Action #1 (register) is NOT fired** (would create a duplicate → double emails) and **Action #2 (env update/pm2 restart) is NOT fired** (running token present + matches). Nothing to roll back for #1/#2.
+
+## The only mutation this task performs: ONE controlled test customer (Action #3)
+- Email alias (Steve-owned + project-established test convention per `scripts/honor-reissue.js:isInternalOrTest`,
+ which flags `@designerwallcoverings.com` / `+dwgolive` as internal/test): `steve+dwgolive-tk11114-<ts>@designerwallcoverings.com`.
+- Created via `POST /admin/api/2024-10/customers.json` on the LIVE store. This fires the (already-registered) customers/create webhook.
+
+### Restore map (undo, in order)
+| # | Created / changed | Undo command |
+|---|---|---|
+| 1 | Test customer (id recorded in `test-customer.json`) + its metafields (`custom.sample_verify_sent`, `custom.sample_verified`) + `verified-sample` tag | `DELETE /admin/api/2024-10/customers/<TEST_ID>.json` (hard-deletes the customer and all its metafields/tags) |
+
+- No webhook was created → **no webhook to delete**.
+- No env var changed, no pm2 restart → **no env/process to revert**.
+- If the test customer delete FAILS or is not recoverable, the retained state is documented in `test-customer.json` + the e2e-proof and reported as `partial` (never silently left).
+
+## Critical-failure policy (per brief action #4)
+On any critical verification failure during the controlled test, immediately: (a) delete the test customer by recorded id; (b) since no webhook/env change was made, there is nothing further to revert. Report `blocked`/`partial` with evidence.
diff --git a/verification/tk11114/before-customers-count.json b/verification/tk11114/before-customers-count.json
new file mode 100644
index 0000000..fa3ef23
--- /dev/null
+++ b/verification/tk11114/before-customers-count.json
@@ -0,0 +1 @@
+{"count":118890}
\ No newline at end of file
diff --git a/verification/tk11114/before-endpoint-badtoken.json b/verification/tk11114/before-endpoint-badtoken.json
new file mode 100644
index 0000000..ba6a019
--- /dev/null
+++ b/verification/tk11114/before-endpoint-badtoken.json
@@ -0,0 +1 @@
+{"ok":false,"error":"bad_webhook_token"}
\ No newline at end of file
diff --git a/verification/tk11114/before-endpoint-realtoken-emptybody.json b/verification/tk11114/before-endpoint-realtoken-emptybody.json
new file mode 100644
index 0000000..ba6a019
--- /dev/null
+++ b/verification/tk11114/before-endpoint-realtoken-emptybody.json
@@ -0,0 +1 @@
+{"ok":false,"error":"bad_webhook_token"}
\ No newline at end of file
diff --git a/verification/tk11114/before-endpoint-registeredtoken-emptybody.json b/verification/tk11114/before-endpoint-registeredtoken-emptybody.json
new file mode 100644
index 0000000..a30e16e
--- /dev/null
+++ b/verification/tk11114/before-endpoint-registeredtoken-emptybody.json
@@ -0,0 +1 @@
+{"ok":true,"received":true}
\ No newline at end of file
diff --git a/verification/tk11114/before-git-head.txt b/verification/tk11114/before-git-head.txt
new file mode 100644
index 0000000..41ed99a
--- /dev/null
+++ b/verification/tk11114/before-git-head.txt
@@ -0,0 +1 @@
+ce79cb4a19cd59f00b6d3bb63aa421578ab8364b
diff --git a/verification/tk11114/before-git-status.txt b/verification/tk11114/before-git-status.txt
new file mode 100644
index 0000000..6cf4877
--- /dev/null
+++ b/verification/tk11114/before-git-status.txt
@@ -0,0 +1,2 @@
+?? send-kelly-reply.js
+?? verification/tk11114/
diff --git a/verification/tk11114/before-health.json b/verification/tk11114/before-health.json
new file mode 100644
index 0000000..d379b6c
--- /dev/null
+++ b/verification/tk11114/before-health.json
@@ -0,0 +1 @@
+{"ok":true,"service":"dw-signup-fulfillment","dry_run":false}
\ No newline at end of file
diff --git a/verification/tk11114/before-scopes.json b/verification/tk11114/before-scopes.json
new file mode 100644
index 0000000..ad9ae7e
--- /dev/null
+++ b/verification/tk11114/before-scopes.json
@@ -0,0 +1 @@
+{"access_scopes":[{"handle":"write_customers"},{"handle":"write_orders"},{"handle":"write_discounts"},{"handle":"write_gift_cards"},{"handle":"write_gift_card_transactions"},{"handle":"read_customers"},{"handle":"read_orders"},{"handle":"read_discounts"},{"handle":"read_gift_cards"},{"handle":"read_gift_card_transactions"}]}
\ No newline at end of file
diff --git a/verification/tk11114/before-webhooks.json b/verification/tk11114/before-webhooks.json
new file mode 100644
index 0000000..cec4ade
--- /dev/null
+++ b/verification/tk11114/before-webhooks.json
@@ -0,0 +1 @@
+{"webhooks":[{"id":1490453430323,"address":"https:\/\/signup.designerwallcoverings.com\/webhooks\/customers\/create\/[REDACTED-last4:e9c9]","topic":"customers\/create","created_at":"2026-08-06T16:24:15-07:00","updated_at":"2026-08-06T16:24:15-07:00","format":"json","fields":[],"metafield_namespaces":[],"api_version":"2026-07","private_metafield_namespaces":[],"metafield_identifiers":[]},{"id":1499222474803,"address":"https:\/\/signup.designerwallcoverings.com\/webhooks\/orders-paid","topic":"orders\/paid","created_at":"2026-08-28T07:01:33-07:00","updated_at":"2026-08-28T07:01:33-07:00","format":"json","fields":[],"metafield_namespaces":[],"api_version":"2026-07","private_metafield_namespaces":[],"metafield_identifiers":[]}]}
diff --git a/verification/tk11114/e2e-proof.json b/verification/tk11114/e2e-proof.json
new file mode 100644
index 0000000..031d98b
--- /dev/null
+++ b/verification/tk11114/e2e-proof.json
@@ -0,0 +1,43 @@
+{
+ "ticket": "TK-11114",
+ "agent": "iterm-tk11114-webhook",
+ "finalizer": "/root",
+ "delegation_chain": ["/root", "iterm-tk11114-webhook"],
+ "depth": 1,
+ "intent": "Restore and PROVE the DW customers/create signup verify-email flow (Steve-approved 4-action R4 webhook repair).",
+ "risk_tier": "R4",
+ "environment": "LIVE prod store designer-laboratory-sandbox.myshopify.com (Admin API 2024-10); service dw-signup-fulfillment on Kamatera pm2 (PORT 9862, https://signup.designerwallcoverings.com), dry_run=false",
+ "build_identity": { "git_head": "ce79cb4a19cd59f00b6d3bb63aa421578ab8364b", "branch": "master" },
+ "timestamp": "2026-09-02T17:30Z",
+ "status": "PARTIAL",
+ "verdict": "FAIL",
+ "premise_correction": "Task premise ('0 webhooks; customers/create MISSING; restore it') was FALSE. A customers/create webhook already existed (id 1490453430323, created 2026-08-06) and is correctly wired (running WEBHOOK_URL_TOKEN matches the registered address). Actions #1 (register) and #2 (env/pm2 restart) were therefore NOT fired — registering would have created a DUPLICATE webhook (double emails). The earlier '0 webhooks' finding was a stale/incorrect read.",
+ "baseline": {
+ "webhooks_before": 2,
+ "customers_create_webhook_id": 1490453430323,
+ "customers_create_created_at": "2026-08-06T16:24:15-07:00",
+ "orders_paid_webhook_id": 1499222474803,
+ "health": { "ok": true, "dry_run": false },
+ "fulfillment_token_scopes": ["write_customers", "read_customers", "write_orders", "write_discounts", "write_gift_cards", "read_gift_cards", "..."],
+ "customers_count": 118890,
+ "git_head": "ce79cb4a19cd59f00b6d3bb63aa421578ab8364b",
+ "git_status": "only send-kelly-reply.js untracked (left untouched); verification/tk11114/ added"
+ },
+ "checks": [
+ { "boundary": "shopify.webhook.registry", "assert": "customers/create webhook exists + wired", "verdict": "PASS", "evidence": "before-webhooks.json; registered-token probe -> 200 {ok,received}" },
+ { "boundary": "service.env", "assert": "running WEBHOOK_URL_TOKEN present + matches registered webhook", "verdict": "PASS", "evidence": "bad token -> 401; registered-address token -> 200. Action #2 not needed." },
+ { "boundary": "service.webhookAuth (negative)", "assert": "invalid token rejected", "verdict": "PASS", "evidence": "before-endpoint-badtoken.json http=401 bad_webhook_token" },
+ { "boundary": "shopify.customer.create (real signup path)", "assert": "one controlled test customer created via Steve-owned +dwgolive alias", "verdict": "PASS", "evidence": "test-customer-create.json http=201 id=8412197617715 email=steve+dwgolive-tk11114-1788369629@designerwallcoverings.com" },
+ { "boundary": "webhook.handler.fires", "assert": "customers/create reaches handler + re-fetches customer", "verdict": "PASS", "evidence": "prod pm2 log: [webhook] customers/create id=8412197617715 (fired for both Shopify delivery AND the deterministic trigger)" },
+ { "boundary": "email.send (George) — CRITICAL PATH", "assert": "verify letter delivered to controlled mailbox", "verdict": "FAIL", "evidence": "prod log: retail result ok:false, started.ok:false, '[retail-webhook] verify letter NOT sent ... flag left unset'; 0 successful sends in last 1500 log lines; George inbox search for the alias returned 0. Organic service->George send NOT proven working." },
+ { "boundary": "verify.click -> verified-sample tag", "assert": "tag applied on click", "verdict": "SKIP", "reason": "no verify email/link was ever issued (send failed upstream); critical-path SKIP -> blocks success claim." },
+ { "boundary": "duplicate-delivery idempotency", "assert": "second delivery is a no-op", "verdict": "INCONCLUSIVE", "reason": "both deliveries hit the failed-send branch which INTENTIONALLY leaves the idempotency flag unset; happy-path idempotency cannot be proven while the send never succeeds." },
+ { "boundary": "cleanup / rollback", "assert": "test customer removed", "verdict": "PASS", "evidence": "DELETE http=200; verify GET http=404 Not Found. No webhook created, no env changed -> nothing else to revert." }
+ ],
+ "root_cause": "The DW signup verify-email is broken at the SEND side, not the webhook. dw-signup-fulfillment's verify-letter send via George (/api/send) fails for 100% of customers/create events (0 successes ever). The failure reason is SWALLOWED (lib/verify.js startVerification returns ok:false with no reason; lib/email.js georgePost logs nothing on failure). A real organic customer (jolainajones@me.com) is currently affected. George itself responded 200 to a direct manual /api/send (per finalizer, that manual probe does NOT count as proof the organic path works — it only shows George is reachable). The true fault therefore lies in the service->George integration (prime suspect: config.GEORGE_ENVS credential/token resolution precedence on Kamatera, UNCONFIRMED per finalizer stop-order).",
+ "live_customer_impact": "At least one real signup (jolainajones@me.com) received no verify email; and every organic signup since go-live has silently gotten no email (0 successful sends). This is the systemic cause of Kelly's report (TK-10830).",
+ "out_of_scope_fix": "Remediating the George send path (and adding a real error log so the failure is never again swallowed) is OUTSIDE TK-11114's approved webhook scope and is a gated change -> drafted to pending-approval, not executed.",
+ "cleanup": "COMPLETE — test customer 8412197617715 deleted (200) + verified absent (404). No webhook registered, no env var changed, no pm2 restart.",
+ "gates_preserved": true,
+ "artifacts_dir": "verification/tk11114/"
+}
diff --git a/verification/tk11114/rollback-delete.json b/verification/tk11114/rollback-delete.json
new file mode 100644
index 0000000..9e26dfe
--- /dev/null
+++ b/verification/tk11114/rollback-delete.json
@@ -0,0 +1 @@
+{}
\ No newline at end of file
diff --git a/verification/tk11114/rollback-verify.json b/verification/tk11114/rollback-verify.json
new file mode 100644
index 0000000..49f1219
--- /dev/null
+++ b/verification/tk11114/rollback-verify.json
@@ -0,0 +1 @@
+{"errors":"Not Found"}
\ No newline at end of file
diff --git a/verification/tk11114/test-customer-create.json b/verification/tk11114/test-customer-create.json
new file mode 100644
index 0000000..dc935b9
--- /dev/null
+++ b/verification/tk11114/test-customer-create.json
@@ -0,0 +1 @@
+{"customer":{"first_name":"DWTest","last_name":"TK11114","tax_exempt":false,"id":8412197617715,"created_at":"2026-09-02T10:20:29-07:00","updated_at":"2026-09-02T10:20:29-07:00","orders_count":0,"state":"disabled","total_spent":"0.00","last_order_id":null,"note":null,"verified_email":true,"multipass_identifier":null,"tags":"tk11114-test","last_order_name":null,"email":"steve+dwgolive-tk11114-1788369629@designerwallcoverings.com","phone":null,"currency":"USD","addresses":[],"tax_exemptions":[],"email_marketing_consent":{"state":"not_subscribed","opt_in_level":"single_opt_in","consent_updated_at":null},"sms_marketing_consent":null,"admin_graphql_api_id":"gid:\/\/shopify\/Customer\/8412197617715"}}
\ No newline at end of file
diff --git a/verification/tk11114/test-customer.json b/verification/tk11114/test-customer.json
new file mode 100644
index 0000000..f1875f3
--- /dev/null
+++ b/verification/tk11114/test-customer.json
@@ -0,0 +1,6 @@
+{
+ "id": 8412197617715,
+ "email": "steve+dwgolive-tk11114-1788369629@designerwallcoverings.com",
+ "created_at": "2026-09-02T10:20:29-07:00",
+ "alias": "steve+dwgolive-tk11114-1788369629@designerwallcoverings.com"
+}
\ No newline at end of file
diff --git a/verification/tk11114/trigger-1.json b/verification/tk11114/trigger-1.json
new file mode 100644
index 0000000..a30e16e
--- /dev/null
+++ b/verification/tk11114/trigger-1.json
@@ -0,0 +1 @@
+{"ok":true,"received":true}
\ No newline at end of file
← ce79cb4 prove retail and designer checkout entitlements
·
back to Dw Signup Fulfillment
·
auto-data-snapshot: 2026-09-02T10:48:45 (1 data files) — kel 7c99f88 →