← back to Dw Marketing Reels
reels IG roster: demote unreachable @grassclothwallpaper to needs-relink (TK-10447)
099834dc92cb029f10700e22dc4aa8c355b75921 · 2026-08-25 11:38:32 -0700 · Steve Abrams
Empirical Graph API verification (read-only, $0) of all 35 'ready' accounts on the
shared durable META token found 34 resolve and 1 does not: ig_user_id 17841408868631110
(@grassclothwallpaper) returns 'Object does not exist / missing permissions' while the
account still exists publicly (HTTP 200) — unlinked from the Page/Business or stale ID.
Added a NEEDS_RELINK manifest to the generator so it's durably demoted to status
'needs-relink' (was falsely 'ready'), preventing a silent publish failure. Roster is now
34 verified-postable + 1 needs-relink + 5 aspirational. Re-link is a gated Meta action.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Files touched
M data/ig-accounts.jsonM scripts/build-ig-accounts.js
Diff
commit 099834dc92cb029f10700e22dc4aa8c355b75921
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Tue Aug 25 11:38:32 2026 -0700
reels IG roster: demote unreachable @grassclothwallpaper to needs-relink (TK-10447)
Empirical Graph API verification (read-only, $0) of all 35 'ready' accounts on the
shared durable META token found 34 resolve and 1 does not: ig_user_id 17841408868631110
(@grassclothwallpaper) returns 'Object does not exist / missing permissions' while the
account still exists publicly (HTTP 200) — unlinked from the Page/Business or stale ID.
Added a NEEDS_RELINK manifest to the generator so it's durably demoted to status
'needs-relink' (was falsely 'ready'), preventing a silent publish failure. Roster is now
34 verified-postable + 1 needs-relink + 5 aspirational. Re-link is a gated Meta action.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---
data/ig-accounts.json | 4 ++--
scripts/build-ig-accounts.js | 46 +++++++++++++++++++++++++++++++-------------
2 files changed, 35 insertions(+), 15 deletions(-)
diff --git a/data/ig-accounts.json b/data/ig-accounts.json
index 1ae3468..1cb3d4a 100644
--- a/data/ig-accounts.json
+++ b/data/ig-accounts.json
@@ -151,9 +151,9 @@
"ig_user_id": "17841408868631110",
"agentUrl": null,
"token_source": "shared-meta-durable",
- "status": "ready",
+ "status": "needs-relink",
"source": "canonical-postable",
- "note": "Postable now on the shared durable META token via scripts/publish-ig.mjs — no per-account creds needed."
+ "note": "Graph GET of stored ig_user_id 17841408868631110 fails on the shared token (unlinked from Page/Business or stale ID); @grassclothwallpaper still exists publicly (HTTP 200). Re-link in Meta Business Manager to restore."
},
{
"id": "ig-hollywoodwallcoverings",
diff --git a/scripts/build-ig-accounts.js b/scripts/build-ig-accounts.js
index e46a9d9..1efbf5b 100644
--- a/scripts/build-ig-accounts.js
+++ b/scripts/build-ig-accounts.js
@@ -30,6 +30,19 @@ const ROOT = join(dirname(fileURLToPath(import.meta.url)), '..');
const CANON = join(ROOT, 'data', 'dw-canonical-accounts.json');
const OUT = join(ROOT, 'data', 'ig-accounts.json');
+// Postable-BY-HANDLE accounts whose IG account is NO LONGER reachable on the shared
+// durable page token — the account still exists publicly but is not (or no longer)
+// linked to the Page/Business this token authorizes, OR the recorded ig_user_id is
+// stale. Empirically confirmed 2026-08-25 (TK-10447): a read-only Graph GET of the
+// stored ig_user_id returns "Object does not exist / missing permissions" while the
+// other 34 resolve on the SAME token. Demoted to status:'needs-relink' so the console
+// does not advertise it as postable and publish-ig.mjs won't silently fail on it.
+// Fix = re-link the IG account to the Page in Meta Business Manager (or capture the
+// correct linked ig_user_id) — a gated Meta identity action. Keyed by handle.
+const NEEDS_RELINK = {
+ grassclothwallpaper: 'Graph GET of stored ig_user_id 17841408868631110 fails on the shared token (unlinked from Page/Business or stale ID); @grassclothwallpaper still exists publicly (HTTP 200). Re-link in Meta Business Manager to restore.',
+};
+
// Brands with NO postable Instagram account yet (handle NOT among the 35 postable).
// These stay pending-creds — the gated work is: create an IG Business account + link
// it to the Meta Business so the shared token covers it. Keyed by handle (or a synthetic
@@ -59,18 +72,23 @@ const idFor = handle => handle === 'designerwallcoverings'
? 'dw'
: 'ig-' + String(handle).toLowerCase().replace(/[^a-z0-9-]+/g, '-');
-const ready = postable.map(a => ({
- id: idFor(a.handle),
- label: a.name || a.handle,
- handle: a.handle,
- business: `${a.handle} · Instagram (Meta Graph)`,
- ig_user_id: a.ig_user_id || null,
- agentUrl: null, // published via scripts/publish-ig.mjs, not the HTTP agent
- token_source: 'shared-meta-durable', // one never-expiring META page token covers all 35
- status: a.ig_user_id ? 'ready' : 'pending-creds',
- source: 'canonical-postable',
- note: 'Postable now on the shared durable META token via scripts/publish-ig.mjs — no per-account creds needed.',
-}));
+const ready = postable.map(a => {
+ const relink = NEEDS_RELINK[String(a.handle).toLowerCase()];
+ return {
+ id: idFor(a.handle),
+ label: a.name || a.handle,
+ handle: a.handle,
+ business: `${a.handle} · Instagram (Meta Graph)`,
+ ig_user_id: a.ig_user_id || null,
+ agentUrl: null, // published via scripts/publish-ig.mjs, not the HTTP agent
+ token_source: 'shared-meta-durable', // one never-expiring META page token covers the postable set
+ status: relink ? 'needs-relink' : (a.ig_user_id ? 'ready' : 'pending-creds'),
+ source: 'canonical-postable',
+ note: relink
+ ? relink
+ : 'Postable now on the shared durable META token via scripts/publish-ig.mjs — no per-account creds needed.',
+ };
+});
// Keep aspirational placeholders that don't collide (by handle) with a postable account.
const postableHandles = new Set(postable.map(a => a.handle.toLowerCase()));
@@ -82,4 +100,6 @@ const out = [...ready, ...pending];
const tmp = OUT + '.tmp';
writeFileSync(tmp, JSON.stringify(out, null, 2) + '\n');
renameSync(tmp, OUT);
-console.log(`wrote data/ig-accounts.json — ${ready.length} postable (ready) + ${pending.length} aspirational (pending-creds)`);
+const readyCount = out.filter(a => a.status === 'ready').length;
+const relinkCount = out.filter(a => a.status === 'needs-relink').length;
+console.log(`wrote data/ig-accounts.json — ${readyCount} postable (ready) + ${relinkCount} needs-relink + ${pending.length} aspirational (pending-creds)`);
← 71d633f chore: reels.json sync + version bump (session close: IG acc
·
back to Dw Marketing Reels
·
auto-data-snapshot: 2026-08-25T14:34:54 (1 data files) — dat 0537a8a →