← back to Tk 10965 Zero Price Analysis
snapshot concurrent zero-price remediation evidence
6696093258b2f5a3f1fc583d2054994546cd021f · 2026-08-30 17:40:45 -0700 · Steve Abrams
Files touched
M apply-fix.mjsA evidence/credential-scope-2026-08-30.jsonM evidence/verify-latest.jsonA verification/e2e-proof.json
Diff
commit 6696093258b2f5a3f1fc583d2054994546cd021f
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Sun Aug 30 17:40:45 2026 -0700
snapshot concurrent zero-price remediation evidence
---
apply-fix.mjs | 23 +++++++++++++---
evidence/credential-scope-2026-08-30.json | 17 ++++++++++++
evidence/verify-latest.json | 2 +-
verification/e2e-proof.json | 44 +++++++++++++++++++++++++++++++
4 files changed, 81 insertions(+), 5 deletions(-)
diff --git a/apply-fix.mjs b/apply-fix.mjs
index 2f0539f..7719680 100644
--- a/apply-fix.mjs
+++ b/apply-fix.mjs
@@ -19,6 +19,8 @@ const val = k => (env.match(new RegExp('^' + k + '=(.*)$', 'm')) || [])[1]?.trim
const DOM = val('SHOPIFY_STORE_DOMAIN'), TOK = val('SHOPIFY_ADMIN_TOKEN');
const API = `https://${DOM}/admin/api/2024-10/graphql.json`;
+if (!DOM || !TOK) throw new Error('Missing SHOPIFY_STORE_DOMAIN or SHOPIFY_ADMIN_TOKEN');
+
async function gql(q, v) {
for (let a = 0; a < 8; a++) {
const r = await fetch(API, { method: 'POST', headers: { 'X-Shopify-Access-Token': TOK, 'Content-Type': 'application/json' }, body: JSON.stringify({ query: q, variables: v }) });
@@ -58,9 +60,18 @@ async function enumerateBad() {
return out;
}
-async function setOnHand(inventoryItemId, locationId, quantity) {
+async function requireInventoryWriteScope() {
+ const d = await gql(`query{currentAppInstallation{accessScopes{handle}}}`, {});
+ const scopes = d.currentAppInstallation.accessScopes.map(s => s.handle).sort();
+ if (!scopes.includes('write_inventory')) {
+ throw new Error(`BLOCKED: token lacks write_inventory (present scopes: ${scopes.join(', ')})`);
+ }
+ return scopes;
+}
+
+async function setOnHand(inventoryItemId, locationId, compareQuantity, quantity) {
const d = await gql(`mutation($input:InventorySetQuantitiesInput!){inventorySetQuantities(input:$input){userErrors{field message code}}}`,
- { input: { name: 'on_hand', reason: 'correction', ignoreCompareQuantity: true, quantities: [{ inventoryItemId, locationId, quantity }] } });
+ { input: { name: 'on_hand', reason: 'correction', quantities: [{ inventoryItemId, locationId, compareQuantity, quantity }] } });
const errs = d.inventorySetQuantities.userErrors;
if (errs && errs.length) throw new Error(JSON.stringify(errs));
}
@@ -69,8 +80,9 @@ const stamp = () => new Date().toISOString().replace(/[:.]/g, '-');
const arg = process.argv[2], arg2 = process.argv[3];
if (arg === '--rollback') {
+ await requireInventoryWriteScope();
const map = JSON.parse(fs.readFileSync(arg2, 'utf8'));
- let n = 0; for (const it of map.items) for (const l of it.levels) { await setOnHand(it.inventoryItemId, l.locationId, l.onHand); n++; }
+ let n = 0; for (const it of map.items) for (const l of it.levels) { await setOnHand(it.inventoryItemId, l.locationId, 0, l.onHand); n++; }
console.log(`ROLLBACK: restored ${n} inventory levels from ${arg2}`);
process.exit(0);
}
@@ -84,6 +96,9 @@ console.log('by vendor:', JSON.stringify(byV));
if (arg === '--enumerate') { console.log('Enumerate-only. No writes.'); process.exit(0); }
+const scopes = await requireInventoryWriteScope();
+console.log(`Inventory write scope verified (${scopes.length} total scopes).`);
+
const limit = arg === '--canary' ? (Number(arg2) || 50) : bad.length;
const target = bad.slice(0, limit);
console.log(`Applying on_hand=0 to ${target.length} products (${arg})...`);
@@ -91,7 +106,7 @@ let done = 0, fail = 0;
for (const b of target) {
try {
if (!b.levels.length) { done++; continue; } // already 0 everywhere
- for (const l of b.levels) await setOnHand(b.inventoryItemId, l.locationId, 0);
+ for (const l of b.levels) await setOnHand(b.inventoryItemId, l.locationId, l.onHand, 0);
done++;
if (done % 100 === 0) console.log(` ...${done}/${target.length}`);
} catch (e) { fail++; console.error(` FAIL ${b.title}: ${e.message}`); }
diff --git a/evidence/credential-scope-2026-08-30.json b/evidence/credential-scope-2026-08-30.json
new file mode 100644
index 0000000..ee12233
--- /dev/null
+++ b/evidence/credential-scope-2026-08-30.json
@@ -0,0 +1,17 @@
+{
+ "ticket": "TK-10963",
+ "checked_at": "2026-08-30T17:37:00-07:00",
+ "shop": "Designer Wallcoverings and Fabrics",
+ "authenticated": true,
+ "api_status": 200,
+ "scopes": [
+ "read_products",
+ "read_publications",
+ "write_products",
+ "write_publications"
+ ],
+ "required_scope": "write_inventory",
+ "can_execute_inventory_remediation": false,
+ "verdict": "BLOCKED",
+ "note": "No secret value is stored in this evidence file. No mutation was attempted."
+}
diff --git a/evidence/verify-latest.json b/evidence/verify-latest.json
index 5f946dd..264dbcb 100644
--- a/evidence/verify-latest.json
+++ b/evidence/verify-latest.json
@@ -1,5 +1,5 @@
{
- "ts": "2026-08-30T21:28:04.435Z",
+ "ts": "2026-08-31T00:39:04.098Z",
"total": 1743,
"qty2026": 1743,
"canary_blind": 462,
diff --git a/verification/e2e-proof.json b/verification/e2e-proof.json
new file mode 100644
index 0000000..2cc7bbd
--- /dev/null
+++ b/verification/e2e-proof.json
@@ -0,0 +1,44 @@
+{
+ "intent": "Revalidate the live zero-price-orderable cohort and execute a restore-map-first CAS canary only when inventory credentials are authorized.",
+ "risk_tier": "R4",
+ "environment": "Designer Wallcoverings Shopify production, read-only preflight",
+ "ticket": "TK-10963",
+ "authorization_ticket": "TK-10979",
+ "timestamp": "2026-08-31T00:39:04.097Z",
+ "baseline": {
+ "affected_total": 1743,
+ "phillipe_romano": 1281,
+ "fentucci_naturals": 462,
+ "quantity_2026": 1743
+ },
+ "checks": [
+ {
+ "boundary": "Shopify authentication and scopes",
+ "verdict": "PASS",
+ "assertion": "Token authenticated with HTTP 200 and scopes were enumerated without exposing the token."
+ },
+ {
+ "boundary": "Inventory authorization",
+ "verdict": "FAIL",
+ "assertion": "Required write_inventory scope is absent; present scopes are read_products, read_publications, write_products, write_publications."
+ },
+ {
+ "boundary": "Live defect cohort",
+ "verdict": "PASS",
+ "assertion": "Read-only verification found exactly 1,743 active zero-price orderable non-sample variants; all 1,743 have quantity 2026."
+ },
+ {
+ "boundary": "Restore-map-first CAS canary",
+ "verdict": "SKIP",
+ "assertion": "Critical path intentionally not attempted because inventory write authorization failed."
+ },
+ {
+ "boundary": "Side effects",
+ "verdict": "PASS",
+ "assertion": "No Shopify mutation, email, paid API, database write, deploy, or schedule change occurred."
+ }
+ ],
+ "overall_verdict": "BLOCKED",
+ "exact_blocker": "SHOPIFY_ADMIN_TOKEN lacks write_inventory.",
+ "safest_next_action": "Provision or route an approved Shopify Admin token with read_products and write_inventory, rerun scope preflight, then run enumerate -> small CAS canary -> read-only verification before any scale-up."
+}
← ae6d884 auto-data-snapshot: 2026-08-30T15:20:13 (1 data files) — tk1
·
back to Tk 10965 Zero Price Analysis
·
paginate zero-price canary variants f46558f →