[object Object]

← back to Dw Sku Integrity

TK-10896: fix remote-shell quoting — feed SQL via stdin not -c (works over ssh)

cab27665acd7229773ec7f7873876827b525de90 · 2026-08-31 01:09:02 -0700 · codex-10896

Over 'ssh <host> psql -c <sql>' the remote bash re-parses the SQL and chokes on
parens/quotes. psql reads stdin when given no -c/-f, identical local + remote.
Fixed in preflight-check.mjs + dwsku-backlog-scan.mjs. 47 tests green. First
canonical Kamatera preflight run now works and CONFIRMS mirror drift: a-s-cr-ation's
planned row is ALREADY_TARGET on Kamatera (dw_sku already populated) while the mirror
showed it blank — Phase-1 self-copies landed on canonical, mirror never got them.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

Files touched

Diff

commit cab27665acd7229773ec7f7873876827b525de90
Author: codex-10896 <steve@designerwallcoverings.com>
Date:   Mon Aug 31 01:09:02 2026 -0700

    TK-10896: fix remote-shell quoting — feed SQL via stdin not -c (works over ssh)
    
    Over 'ssh <host> psql -c <sql>' the remote bash re-parses the SQL and chokes on
    parens/quotes. psql reads stdin when given no -c/-f, identical local + remote.
    Fixed in preflight-check.mjs + dwsku-backlog-scan.mjs. 47 tests green. First
    canonical Kamatera preflight run now works and CONFIRMS mirror drift: a-s-cr-ation's
    planned row is ALREADY_TARGET on Kamatera (dw_sku already populated) while the mirror
    showed it blank — Phase-1 self-copies landed on canonical, mirror never got them.
    
    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---
 dwsku-backlog-scan.mjs | 7 +++++--
 preflight-check.mjs    | 7 +++++--
 2 files changed, 10 insertions(+), 4 deletions(-)

diff --git a/dwsku-backlog-scan.mjs b/dwsku-backlog-scan.mjs
index bb3fc5b..038cd16 100644
--- a/dwsku-backlog-scan.mjs
+++ b/dwsku-backlog-scan.mjs
@@ -34,8 +34,11 @@ const OUT = outArg >= 0 ? argv[outArg + 1] : null;
 const emitPlan = argv.includes('--plan'); // also emit per-row plan JSONL next to --out
 
 function psql(sql) {
-  const args = [...PSQL.slice(1), '-tA', '-F', US, '-R', RS, '-c', sql];
-  const raw = execFileSync(PSQL[0], args, { maxBuffer: 1 << 30, encoding: 'utf8' });
+  // Feed SQL via STDIN, not -c: over `ssh <host> psql ...` the -c argument would be
+  // re-parsed by the REMOTE shell and choke on SQL parens/quotes. psql reads stdin
+  // when given no -c/-f, which works identically local and over ssh.
+  const args = [...PSQL.slice(1), '-tA', '-F', US, '-R', RS];
+  const raw = execFileSync(PSQL[0], args, { input: sql, maxBuffer: 1 << 30, encoding: 'utf8' });
   return raw.split(RS).map((r) => r.replace(/\n$/, '')).filter((r) => r.length).map((r) => r.split(US));
 }
 
diff --git a/preflight-check.mjs b/preflight-check.mjs
index f8b1722..62d15fb 100644
--- a/preflight-check.mjs
+++ b/preflight-check.mjs
@@ -39,8 +39,11 @@ function sqlEscape(v) { return String(v).replace(/'/g, "''"); }
 function defaultChunkReader(shopifyIds) {
   const inList = shopifyIds.map((s) => `'${sqlEscape(s)}'`).join(',');
   const sql = `SELECT shopify_id, coalesce(dw_sku,'') FROM shopify_products WHERE shopify_id IN (${inList});`;
-  const out = execFileSync(PSQL[0], [...PSQL.slice(1), '-tA', '-F', US, '-R', RS, '-c', sql], {
-    maxBuffer: 1 << 30, encoding: 'utf8',
+  // Feed SQL via STDIN, not -c: over `ssh <host> psql ...` the -c argument would be
+  // re-parsed by the REMOTE shell and choke on the SQL's parens/quotes. psql with no
+  // -c/-f reads from stdin, which works identically local and over ssh.
+  const out = execFileSync(PSQL[0], [...PSQL.slice(1), '-tA', '-F', US, '-R', RS], {
+    input: sql, maxBuffer: 1 << 30, encoding: 'utf8',
   });
   const rows = new Map();
   for (const rec of out.split(RS)) {

← e941614 TK-10896: add post-apply verify mode + turnkey per-vendor fi  ·  back to Dw Sku Integrity  ·  TK-10896: CANONICAL correction — mirror was stale, real back 74251ab →