← back to Dw Signup Fulfillment
TK-11411: fail loud on unset PUBLIC_URL before any send, not 11 times after
040121babcd659020a8e38ff72245da8c3e6b7ad · 2026-09-10 11:30:10 -0700 · Steve Abrams
The approved run mailed the 3 trade letters successfully, then failed all 11
retail letters with no_public_url. lib/verify.js was right to refuse - without
PUBLIC_URL the verify link would be a dead localhost URL - but the refusal came
per-customer, after the trade cohort had already gone out, leaving a
half-completed run.
Cause: PUBLIC_URL lives in ecosystem.config.js, which pm2 injects into the
SERVICE. A bare `node scripts/...` does not inherit it. That is the exact
footgun documented at the top of scripts/recover-stuck-apps.js for DRY_RUN - a
comment I had already read today and then repeated with a different variable.
Now pre-flights once, before any send, and prints the correct invocation.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Files touched
M scripts/tk11411-resend.js
Diff
commit 040121babcd659020a8e38ff72245da8c3e6b7ad
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Thu Sep 10 11:30:10 2026 -0700
TK-11411: fail loud on unset PUBLIC_URL before any send, not 11 times after
The approved run mailed the 3 trade letters successfully, then failed all 11
retail letters with no_public_url. lib/verify.js was right to refuse - without
PUBLIC_URL the verify link would be a dead localhost URL - but the refusal came
per-customer, after the trade cohort had already gone out, leaving a
half-completed run.
Cause: PUBLIC_URL lives in ecosystem.config.js, which pm2 injects into the
SERVICE. A bare `node scripts/...` does not inherit it. That is the exact
footgun documented at the top of scripts/recover-stuck-apps.js for DRY_RUN - a
comment I had already read today and then repeated with a different variable.
Now pre-flights once, before any send, and prints the correct invocation.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
---
scripts/tk11411-resend.js | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/scripts/tk11411-resend.js b/scripts/tk11411-resend.js
index 6b06851..b18eb9d 100644
--- a/scripts/tk11411-resend.js
+++ b/scripts/tk11411-resend.js
@@ -65,6 +65,18 @@ function tradeRows() {
console.error('REFUSING --apply while DRY_RUN is on: nothing would actually send. Re-run with DRY_RUN=0.');
process.exit(1);
}
+ // FAIL LOUD, ONCE, BEFORE ANY SEND. PUBLIC_URL lives in ecosystem.config.js, which pm2
+ // injects into the SERVICE — a bare `node scripts/...` does NOT inherit it, so verify.js
+ // refuses every retail send with no_public_url. Without this pre-flight that surfaces as
+ // 11 identical per-customer failures after the trade cohort has already been mailed,
+ // i.e. a half-completed run. Same class as the DRY_RUN footgun documented at the top of
+ // scripts/recover-stuck-apps.js — which I had read, and repeated anyway.
+ if (APPLY && !config.PUBLIC_URL) {
+ console.error('REFUSING --apply: PUBLIC_URL is unset, so every retail verify letter would');
+ console.error('carry a dead localhost link. Run with the value the service uses, e.g.');
+ console.error(" PUBLIC_URL=$(node -e \"console.log(require('./ecosystem.config.js').apps[0].env.PUBLIC_URL)\") DRY_RUN=0 node scripts/tk11411-resend.js --apply");
+ process.exit(1);
+ }
console.log(`TK-11411 resend mode=${APPLY ? 'APPLY' : 'DRY-RUN'} DRY_RUN(config)=${config.DRY_RUN}`);
const rows = tradeRows();
let sent = 0, skipped = 0;
← 1a93bb0 TK-11411: protect the resend ledger from rsync --delete
·
back to Dw Signup Fulfillment
·
TK-11406: sample-ledger counts free units title-agnostically 1de8a86 →