[object Object]

← back to Norma

TK-11383: enforce the designerschat enrollment hold at the PUBLISHER too

72f0976838a43652d9ac83b00bbbdc410eb6a54f · 2026-09-13 11:36:39 -0700 · Steve Abrams

Kimi second-model review of 123570c: a builder-only hold guard is defeated by a
hand-edit of accounts.json, a committed `--include-held` output, an old
checkout, or Meta expanding the pages_show_list allowlist. The irreversible
action — a public post — lives in daily-cadence.js, so the guard belongs there
too, using the mechanism that file already honours.

- account-themes.json: convert the designerschat override from a keyword to a
  `skip`. daily-cadence.js already excludes any handle with a skip
  (eligible = HANDLES.filter(h => !themeFor(h).skip)), so even if designerschat
  re-enters accounts.json by ANY path, the cadence will not post to it.
  A skip can only PREVENT a post, never cause one.
- build-registry.js: a MISSING enrollment-hold.json now warns loudly instead of
  silently failing open (a corrupt file already fails closed). The hard backstop
  for the account that matters is now the publisher-side skip above, which does
  not depend on this file existing.

Verified two independent layers: (1) default rebuild still reproduces the
committed accounts.json with byte-identical records and no designerschat
(set-diff, not a count check — Kimi's nit); (2) injecting designerschat into a
registry via --include-held and running the publisher's exact eligibility logic
excludes it (skip honoured). Nothing posted, no registry rewritten.

Undo: git revert HEAD.

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

Files touched

Diff

commit 72f0976838a43652d9ac83b00bbbdc410eb6a54f
Author: Steve Abrams <steve@designerwallcoverings.com>
Date:   Sun Sep 13 11:36:39 2026 -0700

    TK-11383: enforce the designerschat enrollment hold at the PUBLISHER too
    
    Kimi second-model review of 123570c: a builder-only hold guard is defeated by a
    hand-edit of accounts.json, a committed `--include-held` output, an old
    checkout, or Meta expanding the pages_show_list allowlist. The irreversible
    action — a public post — lives in daily-cadence.js, so the guard belongs there
    too, using the mechanism that file already honours.
    
    - account-themes.json: convert the designerschat override from a keyword to a
      `skip`. daily-cadence.js already excludes any handle with a skip
      (eligible = HANDLES.filter(h => !themeFor(h).skip)), so even if designerschat
      re-enters accounts.json by ANY path, the cadence will not post to it.
      A skip can only PREVENT a post, never cause one.
    - build-registry.js: a MISSING enrollment-hold.json now warns loudly instead of
      silently failing open (a corrupt file already fails closed). The hard backstop
      for the account that matters is now the publisher-side skip above, which does
      not depend on this file existing.
    
    Verified two independent layers: (1) default rebuild still reproduces the
    committed accounts.json with byte-identical records and no designerschat
    (set-diff, not a count check — Kimi's nit); (2) injecting designerschat into a
    registry via --include-held and running the publisher's exact eligibility logic
    excludes it (skip honoured). Nothing posted, no registry rewritten.
    
    Undo: git revert HEAD.
    
    Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
---
 agents/instagram-agent/account-themes.json | 2 +-
 agents/instagram-agent/build-registry.js   | 8 ++++++++
 2 files changed, 9 insertions(+), 1 deletion(-)

diff --git a/agents/instagram-agent/account-themes.json b/agents/instagram-agent/account-themes.json
index c8f89a8..5113d9f 100644
--- a/agents/instagram-agent/account-themes.json
+++ b/agents/instagram-agent/account-themes.json
@@ -189,7 +189,7 @@
     },
     "_email_sweep_note": "Below: owned/active accounts found in the 2026-08-12 email sweep, staged for the moment each IG is connected to its Page (build-registry then enrolls it). Inert until the handle is linked. protestdaily is skip — it's a news/media account, not a wallcovering product feed; give it bespoke content, never the DW-product cadence.",
     "designerschat": {
-      "keyword": "interior design"
+      "skip": "enrollment reverted by Steve (e0dcc47) — linked but deliberately NOT in the public cadence; publisher-side backstop to enrollment-hold.json (TK-11383). If it ever re-enters accounts.json (hand-edit / --include-held / Meta allowlist expansion), daily-cadence still excludes it here."
     },
     "beverlyandhillsdesigns": {
       "keyword": "glamour interior design"
diff --git a/agents/instagram-agent/build-registry.js b/agents/instagram-agent/build-registry.js
index 70532fe..a42331e 100644
--- a/agents/instagram-agent/build-registry.js
+++ b/agents/instagram-agent/build-registry.js
@@ -199,6 +199,14 @@ async function main() {
       process.exit(1);
     }
     holdReadError = 'enrollment-hold.json not present';
+    // Missing (vs corrupt) is fail-OPEN by necessity — an old checkout predating
+    // the file must still build — but it is NOT silent: warn loudly, because
+    // `rm enrollment-hold.json` would otherwise disable this guard quietly. The
+    // hard backstop for the one account that matters (designerschat) is a `skip`
+    // in account-themes.json, which daily-cadence.js (the actual publisher)
+    // honours regardless of this file (Kimi review, TK-11383).
+    console.error('WARNING: enrollment-hold.json is absent — the builder-side hold guard is OFF.');
+    console.error('  The publisher-side skip in account-themes.json still applies; restore this file to re-arm the builder guard.');
   }
   const held = [];
   for (const h of Object.keys(holdMap)) {

← 123570c TK-11383: make build-registry.js stop silently changing who  ·  back to Norma  ·  TK-11383: enforce the enrollment hold at the PUBLISHER too, 3bdc7a5 →