From 5df0e70e4e4c4215940bd29cbc0f8cf80ac8ded2 Mon Sep 17 00:00:00 2001 From: Sweets Sweetman Date: Mon, 6 Jul 2026 16:19:27 -0500 Subject: [PATCH 1/3] feat(social-ship-posts): wire the account story canon (NARRATIVE.md) into the loop Draft step now requires naming which storyline arc and character a post serves (from the account workspace's NARRATIVE.md story bible) before writing copy; the log step records the arc for continuity. Accounts without a canon get flagged to the owner. Grounded in the sweetman account data (2026-07-06 scrape): narrative posts (builder BTS, integrity creed, named-artist earnings) are the consistent winners; launch-framed posts flatline. Co-Authored-By: Claude Fable 5 --- skills/recoup-internal-social-ship-posts/SKILL.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/skills/recoup-internal-social-ship-posts/SKILL.md b/skills/recoup-internal-social-ship-posts/SKILL.md index 290ef92..11967f5 100644 --- a/skills/recoup-internal-social-ship-posts/SKILL.md +++ b/skills/recoup-internal-social-ship-posts/SKILL.md @@ -12,7 +12,7 @@ Authenticate to the Recoup API with an `x-api-key` (`RECOUP_API_KEY`) or `Author ## The loop 1. **Learn** — pull how recent posts performed, so copy is grounded in evidence, not vibes. -2. **Draft** — write topic-first copy that fits the platform and the goal. +2. **Draft** — write topic-first copy that fits the platform, the goal, and the account's story canon. 3. **Decide the CTA** — comment-gate for leads, or direct link for reach. 4. **Publish** — via the connector where supported, or hand off for manual posting. 5. **Log & re-measure** — record what went out; re-pull performance ~48h later. @@ -65,6 +65,8 @@ Read the top performer against the flatliners and name the differences (framing, ## Step 2 — Draft +**Check the story canon first.** If the account workspace has a `NARRATIVE.md` (story bible: premise, recurring cast, storylines), read it and name **which arc and which character this post serves** before writing a word. A post that serves no arc is an ad — reframe it into the story or drop it. Serialized rules live in the canon itself (recurring catchphrases, who may be fictionalized vs. who gets only verified numbers, cliffhanger beats); follow them over generic copy instincts. If the workspace has no `NARRATIVE.md`, note that to the account owner — the account is posting without a story. + Write to the brief from step 1 plus the principles above. Structure that travels well: ``` @@ -113,7 +115,7 @@ Native video works, but the bytes can't go inline: `media` won't fetch a URL, an ## Step 5 — Log and re-measure -Record each post immediately: account, platform, the post id/URN, UTC time, the CTA used, and the copy. Then **re-pull performance ~48h later**: one bulk scrape (step 1) covers all four platforms; add `LINKEDIN_LIST_REACTIONS` only when you need reactor identities, and read gated posts' comment bodies manually. Compare week-over-week — report deltas, not all-time totals. Feed the result back into step 1 for the next post. +Record each post immediately: account, platform, the post id/URN, UTC time, the CTA used, the copy, and — when the account has a `NARRATIVE.md` — **the arc and character the post served** (continuity is what makes the next episode land; an unlogged arc breaks the serial). Then **re-pull performance ~48h later**: one bulk scrape (step 1) covers all four platforms; add `LINKEDIN_LIST_REACTIONS` only when you need reactor identities, and read gated posts' comment bodies manually. Compare week-over-week — report deltas, not all-time totals. Feed the result back into step 1 for the next post. ## Producing a demo video? From ed748e21f14d22035740be166b75d56712054676 Mon Sep 17 00:00:00 2001 From: Sweets Sweetman Date: Mon, 6 Jul 2026 16:33:35 -0500 Subject: [PATCH 2/3] fix(resolver): route the facetime video skill; allow dots in skill slugs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pre-existing drift surfaced by this PR's CI run: the recoup-internal-video-grok-1.5-imagine-facetime skill landed with no RESOLVER.md intent row, failing the no-dark-skills check repo-wide. Adding the row alone wasn't enough — check_resolvable.py's SKILL_TOKEN regex ([a-z0-9-]+) can't match a slug containing a dot, so the skill could never be marked reachable. Widen the regex to accept dot-separated segments and add the Tier 3 route. Co-Authored-By: Claude Fable 5 --- RESOLVER.md | 1 + scripts/check_resolvable.py | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/RESOLVER.md b/RESOLVER.md index 9281ac7..411463e 100644 --- a/RESOLVER.md +++ b/RESOLVER.md @@ -82,6 +82,7 @@ | "recoup-internal" + account-health / account-status snapshot for a Recoup account | `recoup-internal-account-health-report` | | "recoup-internal" + audit scheduled-task email health (what tasks emailed, how many empties the guard blocked) over a window | `recoup-internal-task-email-audit` | | "recoup-internal" + draft/ship/measure LinkedIn or X posts | `recoup-internal-social-ship-posts` | +| "recoup-internal" + FaceTime-call style AI video ad (Grok Imagine 1.5 native-speech clips) | `recoup-internal-video-grok-1.5-imagine-facetime` | --- diff --git a/scripts/check_resolvable.py b/scripts/check_resolvable.py index 2537be2..620d26d 100644 --- a/scripts/check_resolvable.py +++ b/scripts/check_resolvable.py @@ -25,7 +25,8 @@ DEFAULT_PLUGIN = REPO_ROOT # A skill reference in RESOLVER.md is a backtick-wrapped slug: `recoup-foo-bar`. -SKILL_TOKEN = re.compile(r"`(recoup-[a-z0-9-]+)`") +# Dots are allowed mid-slug (e.g. `recoup-internal-video-grok-1.5-imagine-facetime`). +SKILL_TOKEN = re.compile(r"`(recoup-[a-z0-9-]+(?:\.[a-z0-9-]+)*)`") def skill_dirs(plugin: Path) -> set[str]: From b7a30bc2128e21051003950f9fc3197a3dcc070d Mon Sep 17 00:00:00 2001 From: Sweets Sweetman Date: Mon, 6 Jul 2026 16:35:49 -0500 Subject: [PATCH 3/3] fix(resolver-eval): routing fixture for the facetime video skill; dot-safe slug regex Second gate of the same pre-existing drift: the coverage ratchet requires a positive fixture per skill, and run_resolver_eval.py carries its own copy of the dotless SKILL_TOKEN regex, so the facetime skill could neither be routed nor covered. Widen the regex (matching check_resolvable.py) and add the positive fixture with an adversarial 'not' against recoup-content-make-video. All five validate-job steps pass locally. Co-Authored-By: Claude Fable 5 --- resolver-eval.jsonl | 1 + scripts/run_resolver_eval.py | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/resolver-eval.jsonl b/resolver-eval.jsonl index 43bfb1d..49a878a 100644 --- a/resolver-eval.jsonl +++ b/resolver-eval.jsonl @@ -59,6 +59,7 @@ {"intent": "recoup-internal work the valuation funnel and advance this Attio lead", "expected": "recoup-internal-funnel-valuation-pipeline"} {"intent": "recoup-internal account health snapshot for this account", "expected": "recoup-internal-account-health-report"} {"intent": "recoup-internal draft and ship a launch post for LinkedIn and X", "expected": "recoup-internal-social-ship-posts"} +{"intent": "recoup-internal make a FaceTime-call style AI video ad with Grok Imagine", "expected": "recoup-internal-video-grok-1.5-imagine-facetime", "not": ["recoup-content-make-video"]} # --- gating invariant: WITHOUT the recoup-internal keyword, internal skills must NOT fire --- # Only the internal skills with a plausible customer-facing collision get a negative; the dev/eval diff --git a/scripts/run_resolver_eval.py b/scripts/run_resolver_eval.py index 3b53cea..36d77af 100644 --- a/scripts/run_resolver_eval.py +++ b/scripts/run_resolver_eval.py @@ -48,7 +48,8 @@ # Co-located with the plugin root (NOT under tests/, which is gitignored) so the # fixtures ship and CI can run them on a fresh checkout. FIXTURES = PLUGIN / "resolver-eval.jsonl" -SKILL_TOKEN = re.compile(r"`(recoup-[a-z0-9-]+)`") +# Dots are allowed mid-slug (e.g. `recoup-internal-video-grok-1.5-imagine-facetime`). +SKILL_TOKEN = re.compile(r"`(recoup-[a-z0-9-]+(?:\.[a-z0-9-]+)*)`") def skill_dirs() -> set[str]: