{"slug":"dw-marketing-reels","total":90,"limit":100,"offset":0,"since":null,"commits":[{"hash":"ccd338e","date":"2026-07-28 07:28:22 -0700","author":"Steve Abrams","subject":"auto-save: 2026-07-28T07:28:16 (3 files) — data/new-arrivals.json data/reels.json data/video-suggestions.json","body":""},{"hash":"9829533","date":"2026-07-27 20:23:23 -0700","author":"Steve Abrams","subject":"reels: add TIKTOK_DRY_RUN wiring-verify mode for postTikTok (no publish) — TK-00128","body":"dryRunTikTok() exercises the real pre-publish path: token refresh (auth\nplumbing, rotates+persists), creator_info (validates token + reads the\nprivacy levels the app is actually allowed to use), and init-body assembly\n— then STOPS before video/init. Nothing is uploaded, no post is created.\n\nWired into postTikTok as an un-armed escape hatch (TIKTOK_DRY_RUN=1), so the\nwiring can be verified without TIKTOK_LIVE_ARMED and without the pending\nTikTok app audit. Live publish path unchanged and still gated.\n\nOffline test (fetch stubbed, throwaway HOME): SELF_ONLY -> wouldPost true;\nPUBLIC_TO_EVERYONE on unaudited app -> wouldPost false; only token +\ncreator_info called, no init/upload/status. $0 (no live API call).\n\nCo-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>"},{"hash":"e30682f","date":"2026-07-27 17:22:22 -0700","author":"Steve Abrams","subject":"tiktok-audit-demo: turnkey capture runbook for the App-Review demo video (TK-00128)","body":"Scene-by-scene shot list with embedded narration + who-does-what roles (Steve: OAuth\nconsent + account-Private toggle + button clicks; me: cue/narrate/record/trim/split).\nEncodes the unaudited-app trap (account must be Private during the post) and the ≤50MB\nsplit. Readiness verified 2026-07-27. Live capture is a ~10-min guided pass."},{"hash":"bc02a05","date":"2026-07-27 17:15:22 -0700","author":"Steve Abrams","subject":"reels: build TikTok Content-Posting-API uploader (dormant, gated on audit) — TK-00128","body":"- scripts/tiktok-post.mjs: ports the proven FILE_UPLOAD flow (creator_info → init →\n  PUT bytes → poll) from tiktok-oauth-catcher/fire-test-post.sh, plus the token refresh\n  the nightly cron needs (TikTok access tokens expire ~24h; refresh tokens rotate and are\n  persisted back to the canonical secrets .env). Reads creds from secrets (single source).\n- publish-social postTikTok: wired to the uploader behind its OWN gate TIKTOK_LIVE_ARMED,\n  decoupled from IG's SOCIAL_LIVE_ARMED. Dormant → 'ready-pending-tiktok-arm'.\n- privacy defaults SELF_ONLY; refuses a privacy level the app isn't allowed (→ 'pending-audit').\n\nEXTERNAL BLOCKER: the DW production TikTok app is UNAUDITED, so PUBLIC posting is impossible\nuntil TikTok approves the audit (unaudited apps: SELF_ONLY to a private account only). Code is\nready; the first live run is Steve-gated (posts + rotates the shared refresh token).\nVerified: syntax, exports resolve, dry resolution = ready-pending-tiktok-arm, leak gate passes."},{"hash":"eb7ecf5","date":"2026-07-27 16:52:20 -0700","author":"Steve Abrams","subject":"auto-save: 2026-07-27T16:52:13 (1 files) — data/reels.json","body":""},{"hash":"8adb693","date":"2026-07-27 16:46:38 -0700","author":"Steve Abrams","subject":"reels: fix IG async-publish timeout (first live post landed despite 12s client timeout)","body":"First live DW IG reel posted 2026-07-27 (reel/DbUK59zFdfL) but the client saw a 12s\ntimeout mid-publish (IG container->poll->publish runs ~30-60s), recording a false error.\n- bump IG post timeout 12s->90s so a real post is captured as posted.\n- on timeout: return posted-unverified (NOT error) - the request was already sent, so a\n  blind retry would DUPLICATE the post; the dup-guard now skips posted-unverified too.\nReconciled reels[0] to posted (permalink) so the nightly cron cannot double-post.\n\nTK-14."},{"hash":"5121ca1","date":"2026-07-27 16:35:47 -0700","author":"Steve Abrams","subject":"reels: honest TikTok status + FTC content-claims hold guard (pre-arm)","body":"- postTikTok: when armed+token'd but the Content Posting API uploader isn't built,\n  return status 'not-implemented' + console.warn instead of a silent 'pending-reconnect'\n  that could read as handled on an armed run (contrarian: silent-success bomb).\n- Content-claims gate (comms-compliance Fix 1): HOLD any reel whose caption carries an\n  unsubstantiated factual claim ('For 25 years', 'As seen in AD/Elle Decor/WSJ') — status\n  'held-claims-review' — until CLAIMS_SUBSTANTIATED=1. Verified: holds exactly the 3\n  dw-brand-promo reels (15-17), none of the other 30. Fail-safe default = hold.\n\nTK-14. Lets Steve arm the pipeline WITHOUT the unsubstantiated promo reels posting."},{"hash":"19e8ca4","date":"2026-07-27 16:20:45 -0700","author":"Steve Abrams","subject":"reels: consolidate LEAK_DENY to one canonical-synced module + fail-closed leak gate","body":"- scripts/leak-deny.mjs: single source of truth for the private-label denylist,\n  synced to canonical dw-leak-scanner. Adds names the 3 hand-copied regexes had\n  DRIFTED and were missing: lillian august (leaked 2026-07-06), rigo, rigowall.\n  Per-term anchoring: leading-\\b on 'versa' (catches standalone + concatenated,\n  safe on Adversarial/conversation/Universal), both-\\b on 'rigo' (protects Rigoletto).\n- build-reel / build-colorwheel-reel / fetch-new-arrivals: import the shared module,\n  removing 3 drift-prone copies.\n- scripts/scan-leaks.mjs + npm 'scan': fail-closed gate over the staged manifests.\n- cron-run.sh: run the gate BEFORE publish+push — a leaked name can no longer reach\n  a public post. Turns the old one-shot '0 leaks' assertion into a standing gate.\n\nVerified: 22/22 leak+FP assertions pass; gate PASSES on the 33 staged reels.\nTK-14. Contrarian-gated (FIX FIRST verdict applied)."},{"hash":"4f97f1f","date":"2026-07-27 16:05:59 -0700","author":"Steve Abrams","subject":"reels: guard against duplicate social post of an already-'posted' reels[0] on nightly re-run","body":"comms-compliance find (TK-14): main() always takes reels[0]; if a nightly build\nfails to prepend a new reel but publish-social still runs, an already-posted reel\nwould be resubmitted to the Graph API (duplicate public post). Skip only a confirmed\n'posted'/'already-posted' state; every non-terminal state (pending-creds/\nready-pending-arm/error) is still (re)attempted. Full idempotency-key dedup for the\nerror-response-leg edge is a follow-up. Contrarian-gated.\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>"},{"hash":"be479b7","date":"2026-07-27 07:18:52 -0700","author":"Steve Abrams","subject":"auto-save: 2026-07-27T07:18:47 (3 files) — data/new-arrivals.json data/reels.json data/video-suggestions.json","body":""},{"hash":"2cae939","date":"2026-07-26 07:11:26 -0700","author":"Steve Abrams","subject":"auto-save: 2026-07-26T07:11:20 (3 files) — data/new-arrivals.json data/reels.json data/video-suggestions.json","body":""},{"hash":"d9aab81","date":"2026-07-25 07:34:48 -0700","author":"Steve Abrams","subject":"auto-save: 2026-07-25T07:34:42 (3 files) — data/new-arrivals.json data/reels.json data/video-suggestions.json","body":""},{"hash":"689fe27","date":"2026-07-24 08:38:38 -0700","author":"Steve Abrams","subject":"chore: vN patch (session close — image backfill)","body":""},{"hash":"8d53d7f","date":"2026-07-24 08:36:42 -0700","author":"Steve","subject":"record completed image backfill: upload-imageless-11 (11/11 EUR SKUs imaged, Steve-approved live Shopify write, verified in mirror)","body":"Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>"},{"hash":"5ebec05","date":"2026-07-24 07:26:19 -0700","author":"Steve Abrams","subject":"auto-save: 2026-07-24T07:26:03 (3 files) — data/new-arrivals.json data/reels.json data/video-suggestions.json","body":""},{"hash":"d86340e","date":"2026-07-23 11:41:50 -0700","author":"Steve Abrams","subject":"Pin autonomous Claude CLI invocation to Opus (--model opus)","body":"Bare 'claude' spawn inherited the CLI's drifting default model; pin to Opus\nso this build/gen loop always runs on the intended model.\n\nCo-Authored-By: Claude Fable 5 <noreply@anthropic.com>"},{"hash":"acc7a77","date":"2026-07-23 07:19:23 -0700","author":"Steve Abrams","subject":"auto-save: 2026-07-23T07:19:17 (3 files) — data/new-arrivals.json data/reels.json data/video-suggestions.json","body":""},{"hash":"ce006d6","date":"2026-07-22 08:14:06 -0700","author":"Steve","subject":"chore: lint, refactor, v0.8.0 (session close)","body":"- video-runner: hoist prompt(j) to a single const (drop duplicate call in retry loop)\n- lint pass: 0 autofixes needed; flagged pre-existing serveFile Range-header\n  null-deref for a future scoped fix (not session code)"},{"hash":"d385b43","date":"2026-07-22 07:48:24 -0700","author":"Steve","subject":"Route 9:16 catalog reels through build-reel.mjs ($0, IG-publishable, gallery-visible)","body":"Running a real render exposed that new-arrivals-reel via claude -p was slow\n(~8min), cost API, produced a SILENT reel, and orphaned it in output/ (invisible\nto the gallery). The repo's own build-reel.mjs renders the same reel in ~20s, $0\n(local ffmpeg/Chrome), with an IG-publishable AAC track, straight into reels/.\n- video-runner: new-arrivals-reel@9:16 → build-reel.mjs (no arming needed);\n  1:1 + url/newsletter keep the gated claude -p skill path; retry wraps both\n- server: /api/videos gallery now also scans output/ (+ serve guard) so the\n  HyperFrames url/newsletter renders that land there are visible + playable"},{"hash":"f9fdb8f","date":"2026-07-22 07:42:28 -0700","author":"Steve Abrams","subject":"auto-save: 2026-07-22T07:42:20 (3 files) — data/video-jobs.json data/video-suggestions.json output/","body":""},{"hash":"8227e20","date":"2026-07-22 07:33:08 -0700","author":"Steve","subject":"video-runner: give renders narrated audio via auto-resolved HYPERFRAMES_PYTHON","body":"Auto-resolve the local HyperFrames TTS venv (~/.hyperframes/tts-venv/bin/python)\nand inject it only into the render child's env — so auto-rendered reels get\nvoiceover/BGM without arming or mutating the pm2/server environment. Honours an\nexplicit HYPERFRAMES_PYTHON if already set."},{"hash":"6eb3061","date":"2026-07-22 07:13:20 -0700","author":"Steve","subject":"Harden video-runner: retry transient API rate-limits before erroring","body":"Root cause of the studio host's 'claude exit 1' renders was a transient Anthropic\nthrottle ('Server is temporarily limiting requests'), which permanently killed the\njob with no retry. Now:\n- capture claude stderr, classify transient (rate-limit/overloaded/429/529/reset)\n- retry with exponential backoff (VIDEO_MAX_TRIES=3, VIDEO_BACKOFF_MS=20000)\n- record attempts + a human-readable reason in job.note (not opaque 'exit 1')\n- console surfaces the last few errored renders with their reason so failures\n  don't vanish silently\nApplies to both the manual studio buttons and the new suggestions 'Use it' flow."},{"hash":"c0278de","date":"2026-07-22 07:12:15 -0700","author":"Steve Abrams","subject":"auto-save: 2026-07-22T07:12:00 (3 files) — data/new-arrivals.json data/reels.json scripts/video-runner.mjs","body":""},{"hash":"96a00f6","date":"2026-07-22 07:06:32 -0700","author":"Steve","subject":"Add hypergen daily video-suggestions tab (4 ideas/day, dated + used-stamp)","body":"- scripts/suggest-videos.mjs: $0-local daily generator, 4 ideas/day from\n  New Arrivals catalog, append-only history, idempotent per PT date\n- server.js: GET /api/video/suggestions, POST /api/video/suggest,\n  POST /api/video/suggestions/use (queues the render + stamps used_at/used_where);\n  shared buildVideoJob/enqueueVideoJob helpers reused by the manual queue door\n- public/index.html: Suggested-videos tab — day-grouped cards, created date+time\n  chip, Use-it button, and a when/where used-stamp; gated on allowBuild\n- com.steve.dw-video-suggest launchd agent: fills today's 4 daily at 7:05 PT (ideas only)"},{"hash":"aea6ea1","date":"2026-07-21 07:36:24 -0700","author":"Steve Abrams","subject":"auto-save: 2026-07-21T07:36:20 (2 files) — data/new-arrivals.json data/reels.json","body":""},{"hash":"f9ce647","date":"2026-07-20 13:21:47 -0700","author":"Steve","subject":"chore: colorwheel-reel builder cleanup + dl warn (session close)","body":""},{"hash":"c1c43c6","date":"2026-07-20 12:47:12 -0700","author":"Steve","subject":"Fix Threads post: reposted shop-by-color with correct caption (old mismatched post pending manual delete)","body":""},{"hash":"59fcd75","date":"2026-07-20 11:54:24 -0700","author":"Steve","subject":"Shop-by-color reel also posted to Threads (video)","body":""},{"hash":"4d8994e","date":"2026-07-20 10:03:47 -0700","author":"Steve Abrams","subject":"chore: v0.6.0 — /showcase brand-films gallery (session close)","body":""},{"hash":"af86e6b","date":"2026-07-20 07:30:44 -0700","author":"Steve Abrams","subject":"auto-save: 2026-07-20T07:30:40 (2 files) — data/new-arrivals.json data/reels.json","body":""},{"hash":"d028c21","date":"2026-07-19 07:25:21 -0700","author":"Steve Abrams","subject":"auto-save: 2026-07-19T07:25:16 (2 files) — data/new-arrivals.json data/reels.json","body":""},{"hash":"e5e041b","date":"2026-07-18 07:20:16 -0700","author":"Steve Abrams","subject":"auto-save: 2026-07-18T07:20:11 (2 files) — data/new-arrivals.json data/reels.json","body":""},{"hash":"f3f78cd","date":"2026-07-17 19:47:34 -0700","author":"Steve Abrams","subject":"auto-save: 2026-07-17T19:47:29 (1 files) — package-lock.json","body":""},{"hash":"e86b958","date":"2026-07-17 10:31:02 -0700","author":"Steve","subject":"Shop-by-color reel posted: Instagram + Bluesky live; Facebook blocked on token scope","body":""},{"hash":"42687b8","date":"2026-07-17 10:26:14 -0700","author":"Steve Abrams","subject":"add public /showcase brand-films gallery page (all 6 promo cuts)","body":""},{"hash":"8c77003","date":"2026-07-17 10:21:55 -0700","author":"Steve","subject":"Add shop-by-color reel builder — opens on the color wheel (frame-0 thumbnail fix)","body":""},{"hash":"579b3f6","date":"2026-07-17 10:04:49 -0700","author":"Steve Abrams","subject":"chore: v0.5.0 (session close) — Video Studio + color-index hardening","body":""},{"hash":"f801707","date":"2026-07-17 10:04:49 -0700","author":"Steve Abrams","subject":"reels.json: record IG publish (new-arrivals-audio reel → posted, instagram.com/reel/Da5sp25DyRu)","body":""},{"hash":"5408290","date":"2026-07-17 09:46:47 -0700","author":"Steve Abrams","subject":"add platform-tailored IG + TikTok captions to brand-promo reels","body":""},{"hash":"9651df2","date":"2026-07-17 09:46:47 -0700","author":"Steve Abrams","subject":"point deploy health-check at public /privacy (true 200, not auth 401)","body":""},{"hash":"dcec44c","date":"2026-07-17 09:43:31 -0700","author":"Steve Abrams","subject":"stage DW brand promo 15s short cut (3 aspects) into marketing reels panel","body":""},{"hash":"5f5394e","date":"2026-07-17 09:22:41 -0700","author":"Steve Abrams","subject":"5x: report — 4 sweeps; fixed preload storm + console persistence (pm2); M3 'JS error' verified benign (video-preload ERR_ABORTED, no real error)","body":""},{"hash":"eba4f19","date":"2026-07-17 09:15:24 -0700","author":"Steve Abrams","subject":"5x sweep 2: gallery videos preload=none — kills the 21-video simultaneous metadata-preload storm (ERR_ABORTED noise); videos still play on click","body":""},{"hash":"55e44f8","date":"2026-07-17 09:07:23 -0700","author":"Steve Abrams","subject":"deploy: cert-safe nginx script to add public /reels/*.mp4 passthrough to the live marketing.dw vhost (enables Meta media-fetch for IG publishing)","body":""},{"hash":"878597b","date":"2026-07-17 09:04:51 -0700","author":"Steve Abrams","subject":"fix .deploy.conf health-check port 9848→9600 (reels app real port; 9848 is corkwallcovering)","body":""},{"hash":"463adc4","date":"2026-07-17 09:01:08 -0700","author":"Steve Abrams","subject":"console: relative studio-media URL so the video gallery works inside the MCC iframe proxy (/api/reels/ui)","body":""},{"hash":"8ed53f5","date":"2026-07-17 08:53:22 -0700","author":"Steve Abrams","subject":"stage DW brand promo (3 aspects) into marketing reels panel","body":""},{"hash":"f0a2257","date":"2026-07-17 08:40:46 -0700","author":"Steve Abrams","subject":"DW New Arrivals collection-reveal reel (9:16, product-launch-video/HyperFrames): 8-frame cartesian storyboard + frames, Kokoro VO + MusicGen BGM, captions, transitions","body":""},{"hash":"d648cd2","date":"2026-07-17 08:08:28 -0700","author":"Steve Abrams","subject":"video-studio hardening (contrarian FIX-FIRST): realpathSync kills symlink escape on /studio-media + public /reels/; https-URL/.eml validation + 20-job cap on queue; runner requires CLAUDE_BIN & fails loud (no silent ENOENT); job chips show created-time + host-not-armed warning","body":""},{"hash":"f2f4363","date":"2026-07-17 08:01:36 -0700","author":"Steve Abrams","subject":"New Arrivals reel: 7 curated heroes + local Kokoro VO + MusicGen BGM (/bin/zsh)","body":"- Curated 7 hero picks (1-2 colorways/pattern) across Rebel Walls murals + Thibaut\n- 1080x1920 9:16, 22.8s, yuv420p 30fps, AAC 44.1kHz\n- Real local audio: Kokoro TTS voiceover (bf_isabella) over ducked MusicGen ambient bed\n- Fixed banned-word: caption hashtags now #Wallcovering/#Wallcoverings (was #Wallpaper)\n\nCo-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>"},{"hash":"1d2a1cb","date":"2026-07-17 07:58:46 -0700","author":"Steve Abrams","subject":"console: Video Studio — buttons to queue IG reel / URL→reel / newsletter→video + rendered-video gallery (/api/videos) + gated runner (VIDEO_AUTORUN off = waits for studio session; never auto-posts)","body":""},{"hash":"f7b3987","date":"2026-07-16 11:40:44 -0700","author":"Steve","subject":"shop-by-color wheel: -50% wheel+dots, mobile+touch, >=80 SKUs (min:80), add-sample-to-cart per card","body":""},{"hash":"907a60d","date":"2026-07-16 11:26:05 -0700","author":"Steve","subject":"colorwheel: canonical /pages/shop-by-color body (new wheel, replaces static swatch page); /pages/colors 301→shop-by-color","body":""},{"hash":"1dfe5d5","date":"2026-07-16 11:01:54 -0700","author":"Steve","subject":"colorwheel: Shopify /pages/colors widget (scoped inline build, hits public color-widen API)","body":""},{"hash":"5f28b85","date":"2026-07-16 10:43:01 -0700","author":"Steve","subject":"colorwheel: add 6-dot palette below wheel, paginated left/right through 24 curated colors","body":""},{"hash":"8098337","date":"2026-07-16 10:39:10 -0700","author":"Steve","subject":"colorwheel: widen to 15% ΔE band (big data set), fix spin/click color mismatch, drop hex+count, center dot = picked color","body":""},{"hash":"5ca3fe3","date":"2026-07-16 10:26:23 -0700","author":"Steve Abrams","subject":"shop-by-color motion wheel (local preview :9851, proxies live color-index endpoint) + drafted 12-image Shopify upload script (Steve-run/gated)","body":""},{"hash":"51d3d22","date":"2026-07-16 08:15:39 -0700","author":"Steve Abrams","subject":"Source real product images for 12/14 imageless DW products via Browserbase (O&L family blocked host bypass)","body":""},{"hash":"979735d","date":"2026-07-16 08:12:09 -0700","author":"Steve Abrams","subject":"auto-save: 2026-07-16T08:12:03 (9 files) — fetch-ol-images.cjs fetch-ol-manifest.json fetch-remaining.cjs fetch-remaining.json harvest-colorways-results.json","body":""},{"hash":"cc29f33","date":"2026-07-16 07:11:53 -0700","author":"Steve Abrams","subject":"auto-save: 2026-07-16T07:11:48 (2 files) — data/new-arrivals.json data/reels.json","body":""},{"hash":"55f1b05","date":"2026-07-15 14:07:20 -0700","author":"Steve Abrams","subject":"chore: v0.4.1","body":""},{"hash":"eae2436","date":"2026-07-15 14:07:10 -0700","author":"Steve Abrams","subject":"auto-save: 2026-07-15T14:07:06 (2 files) — public/index.html server.js","body":""},{"hash":"2cd59c0","date":"2026-07-15 13:55:34 -0700","author":"Steve Abrams","subject":"chore: v0.4.0 (session close) — FB-graph IG publish + publish-ig.mjs + privacy/terms + audio-mux fix","body":"Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>"},{"hash":"15079e2","date":"2026-07-15 12:34:15 -0700","author":"Steve Abrams","subject":"Add self-contained scripts/publish-ig.mjs — post a reel to IG from the marketing project via the FB-graph flow (durable page token), no Norma dependency; SOCIAL_LIVE_ARMED-gated with a public-media reachability guard","body":"Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>"},{"hash":"c5afbac","date":"2026-07-15 07:35:16 -0700","author":"Steve Abrams","subject":"auto-save: 2026-07-15T07:35:12 (2 files) — data/new-arrivals.json data/reels.json","body":""},{"hash":"390b976","date":"2026-07-14 09:14:44 -0700","author":"Steve Abrams","subject":"Add public /privacy + /terms pages (no-auth) for Meta app publish requirement","body":"Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>"},{"hash":"59b2d6b","date":"2026-07-14 09:04:59 -0700","author":"Steve Abrams","subject":"build-reel: mux silent AAC track into every reel — IG Reels require audio (no-audio MP4 fails Meta processing w/ error 2207082)","body":"Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>"},{"hash":"7d816dd","date":"2026-07-14 07:29:49 -0700","author":"Steve Abrams","subject":"auto-save: 2026-07-14T07:29:44 (2 files) — data/new-arrivals.json data/reels.json","body":""},{"hash":"ac1da40","date":"2026-07-13 15:44:48 -0700","author":"Steve Abrams","subject":"Add package-lock.json — unblocks deploy (npm ci requires a lockfile; project is zero-dep)","body":"Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>"},{"hash":"9ed9b0f","date":"2026-07-13 14:51:39 -0700","author":"Steve Abrams","subject":"New Arrivals reel (2026-07-13-21-49) + refreshed feed (24 arrivals)","body":"Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>"},{"hash":"66cb716","date":"2026-07-13 14:51:32 -0700","author":"Steve Abrams","subject":"Fix console port default 9846->9848 (matches .deploy.conf + README) — 9846 silently collided with live dw-staged-active-viewer","body":"Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>"},{"hash":"d02c9bb","date":"2026-07-13 10:29:15 -0700","author":"Steve Abrams","subject":"Fix publish-status unwrap: read Norma's .result envelope + explicit r.simulated (kills false 'posted' on no-creds + false 'simulated' on live post) + no-creds badge — contrarian gate","body":""},{"hash":"fea25bd","date":"2026-07-13 10:13:38 -0700","author":"Steve Abrams","subject":"chore: v0.3.0 — multi-account IG picker + meta-token canary + live-post payload fix (session close)","body":""},{"hash":"d9ccbc0","date":"2026-07-13 08:23:43 -0700","author":"Steve Abrams","subject":"auto-save: 2026-07-13T08:23:39 (1 files) — data/reels.json","body":""},{"hash":"aa4f29e","date":"2026-07-13 08:13:03 -0700","author":"Steve Abrams","subject":"5 themed reels (Thibaut, Grasscloth Edit, Phillip Jeffries, Statement Murals, Schumacher) + fetch upgrades: leak-deny filter at feed level, multi-page collection fetch, spread sampling, Repeat-spec title cleanup","body":"Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>"},{"hash":"34da727","date":"2026-07-13 07:23:30 -0700","author":"Steve Abrams","subject":"auto-save: 2026-07-13T07:23:25 (2 files) — data/new-arrivals.json data/reels.json","body":""},{"hash":"4321527","date":"2026-07-13 01:59:01 -0700","author":"Steve Abrams","subject":"Pin SOCIAL_LIVE_ARMED=0 in nightly plist — schedule can never inherit an armed env (contrarian hardening)","body":""},{"hash":"829f7fe","date":"2026-07-13 01:58:31 -0700","author":"Steve Abrams","subject":"Fix live-post payload: send video_url (Norma reel.js contract), not mediaUrl — contrarian-caught silent 500","body":""},{"hash":"f6b331e","date":"2026-07-13 01:21:57 -0700","author":"Steve Abrams","subject":"auto-save: 2026-07-13T01:21:52 (3 files) — data/new-arrivals.json data/reels.json scripts/fetch-new-arrivals.mjs","body":""},{"hash":"2db6c90","date":"2026-07-13 00:50:31 -0700","author":"Steve Abrams","subject":"docs: publish-social — reels now public (media blocker cleared), only SOCIAL_LIVE_ARMED remains","body":""},{"hash":"2c90228","date":"2026-07-13 00:44:18 -0700","author":"Steve Abrams","subject":"chore: lint, refactor (hoist SLUG), doc outroBig, v0.2.0 (session close)","body":""},{"hash":"582f1f1","date":"2026-07-13 00:09:27 -0700","author":"Steve Abrams","subject":"Multi-account Instagram picker: DW-family account registry + per-reel Post-to selector + account-routed publish","body":""},{"hash":"808fac7","date":"2026-07-13 00:00:11 -0700","author":"Steve Abrams","subject":"Dry-run publish status for cork reel: IG ready-pending-arm (media URL public), TikTok pending-reconnect","body":""},{"hash":"78da8fd","date":"2026-07-12 23:09:21 -0700","author":"Steve Abrams","subject":"Themeable reels + Phillipe Romano cork reel (env-driven copy/caption/slug + vendor/title/dedupe fetch filters)","body":""},{"hash":"2f74ee0","date":"2026-07-12 12:00:19 -0700","author":"Steve Abrams","subject":"Safety-when-on: ARMED gate (no live post until SOCIAL_LIVE_ARMED=1) + private-label leak filter in captions (contrarian fixes)","body":""},{"hash":"1584e5c","date":"2026-07-12 11:56:01 -0700","author":"Steve Abrams","subject":"Public media exemption: GET /reels/*.mp4 unauthenticated (console/APIs stay gated) — so Meta/TikTok can fetch reels","body":""},{"hash":"20c8b48","date":"2026-07-12 11:21:59 -0700","author":"Steve Abrams","subject":"Auto-post to IG/TikTok (fail-safe pending-creds) + captions + publish-status panel","body":""},{"hash":"a1ba7d4","date":"2026-07-12 10:31:09 -0700","author":"Steve Abrams","subject":"Build-gate for read-only public deploy + nightly push to Kamatera","body":""},{"hash":"7630cbd","date":"2026-07-12 10:21:03 -0700","author":"Steve Abrams","subject":"Add nightly runner (gated plist), README, deploy config","body":""},{"hash":"fc8c20e","date":"2026-07-12 10:20:18 -0700","author":"Steve Abrams","subject":"DW Marketing new-arrivals reels: HyperFrames reel generator + auth-gated console (:9848)","body":""}]}