← back to Ticket System
snapshot before TK-11443 parser fix
ededd12be037067dcd8bd84d334e31c6f55e8a34 · 2026-09-10 17:39:27 -0700 · Steve Abrams
Files touched
A data/claude-run-11175/evidence/TK-11175-20260910T143730Z/tk11175-api-liveness-probe.mjs
Diff
commit ededd12be037067dcd8bd84d334e31c6f55e8a34
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Thu Sep 10 17:39:27 2026 -0700
snapshot before TK-11443 parser fix
---
.../tk11175-api-liveness-probe.mjs | 41 ++++++++++++++++++++++
1 file changed, 41 insertions(+)
diff --git a/data/claude-run-11175/evidence/TK-11175-20260910T143730Z/tk11175-api-liveness-probe.mjs b/data/claude-run-11175/evidence/TK-11175-20260910T143730Z/tk11175-api-liveness-probe.mjs
new file mode 100644
index 00000000..a168cd63
--- /dev/null
+++ b/data/claude-run-11175/evidence/TK-11175-20260910T143730Z/tk11175-api-liveness-probe.mjs
@@ -0,0 +1,41 @@
+// TK-11175 READ-ONLY liveness probe. GET-only. No writes, no spend, no mutation.
+// Answers: is Content API for Shopping v2.1 still serving on 2026-09-10, and is Merchant API v1 serving?
+import fs from 'fs'; import crypto from 'crypto';
+const HOME = process.env.HOME;
+const SA_PATH = HOME + '/Projects/secrets-manager/gmc-sa-146735262.json';
+const MERCHANT = '146735262';
+const b64 = b => Buffer.from(b).toString('base64').replace(/=/g,'').replace(/\+/g,'-').replace(/\//g,'_');
+async function mcToken(){
+ const SA = JSON.parse(fs.readFileSync(SA_PATH,'utf8'));
+ const now = Math.floor(Date.now()/1000);
+ const si = b64(JSON.stringify({alg:'RS256',typ:'JWT'}))+'.'+b64(JSON.stringify({iss:SA.client_email,scope:'https://www.googleapis.com/auth/content',aud:'https://oauth2.googleapis.com/token',iat:now,exp:now+3600}));
+ const s = crypto.createSign('RSA-SHA256'); s.update(si); const jwt = si+'.'+b64(s.sign(SA.private_key));
+ const r = await fetch('https://oauth2.googleapis.com/token',{method:'POST',headers:{'Content-Type':'application/x-www-form-urlencoded'},body:new URLSearchParams({grant_type:'urn:ietf:params:oauth:grant-type:jwt-bearer',assertion:jwt})});
+ const j = await r.json(); if(!j.access_token) throw new Error('token fail: '+JSON.stringify(j).slice(0,200)); return j.access_token;
+}
+const t = await mcToken(); const H = { Authorization: 'Bearer '+t };
+const probes = [
+ ['CONTENT_v2.1 productstatuses', `https://shoppingcontent.googleapis.com/content/v2.1/${MERCHANT}/productstatuses?maxResults=1`],
+ ['CONTENT_v2.1 products', `https://shoppingcontent.googleapis.com/content/v2.1/${MERCHANT}/products?maxResults=1`],
+ ['MERCHANT_v1 products', `https://merchantapi.googleapis.com/products/v1/accounts/${MERCHANT}/products?pageSize=1`],
+ ['MERCHANT_v1 accounts/issues', `https://merchantapi.googleapis.com/accounts/v1/accounts/${MERCHANT}/issues`],
+];
+const out = [];
+for (const [name,url] of probes){
+ try {
+ const r = await fetch(url,{headers:H});
+ const body = await r.text();
+ let shape = 'empty';
+ try { const j = JSON.parse(body);
+ if (j.error) shape = 'ERROR: '+(j.error.status||'')+' '+String(j.error.message||'').slice(0,110);
+ else if (j.resources) shape = `OK resources=${j.resources.length}`;
+ else if (j.productStatuses) shape = `OK productStatuses=${j.productStatuses.length}`;
+ else if (j.products) shape = `OK products=${j.products.length}`;
+ else if (j.accountIssues) shape = `OK accountIssues=${(j.accountIssues||[]).length}`;
+ else shape = 'OK keys=['+Object.keys(j).join(',')+']';
+ } catch { shape = 'non-JSON len='+body.length; }
+ out.push({name, http:r.status, shape});
+ } catch(e){ out.push({name, http:'NETERR', shape:String(e.message).slice(0,110)}); }
+}
+console.log('probe_at=' + new Date().toISOString());
+for (const o of out) console.log(String(o.http).padEnd(7), o.name.padEnd(32), o.shape);
← 79f4475a auto-data-snapshot: 2026-09-10T17:34:11 (1 data files) — dat
·
back to Ticket System
·
governance(TK-11370): make live-by-default Shopify writers d 00df756a →