Skill Tracer
Skills › Knowledge Work Plugins › social-content-engine › gotchas.md

gotchas.md

447 lines · small-business/skills/social-content-engine/reference/gotchas.md at 2574e29

Open on GitHub

Most marks come from matching words in the file, so treat them as pointers.

1# Gotchas
2
3Common failure modes for the social-content-engine skill.
4
5---
6

Gotchas

Common failure modes for the social-content-engine skill.


Raw lines 1 to 6
7## Gotcha: Rebuilding the calendar instead of extending it
8
9**Why it matters:** The calendar is the durable artifact — it is the reason
10this is a content operation and not a campaign generator. When each run starts
11from a blank calendar, the owner re-approves dates they already approved, and
12posts that were scheduled last month quietly get duplicated or dropped.

Gotcha: Rebuilding the calendar instead of extending it

Why it matters: The calendar is the durable artifact — it is the reason this is a content operation and not a campaign generator. When each run starts from a blank calendar, the owner re-approves dates they already approved, and posts that were scheduled last month quietly get duplicated or dropped.

Raw lines 7 to 13
14### ✗ Bad
16```
17Owner: "Give me another month of posts."
18→ Build a fresh 30-day calendar from scratch.
19→ Two rows collide with posts already scheduled in HubSpot.
20```

✗ Bad

Owner: "Give me another month of posts."
→ Build a fresh 30-day calendar from scratch.
→ Two rows collide with posts already scheduled in HubSpot.
Raw lines 14 to 21
22### ✓ Good
24```
25Open the existing calendar first, then report:
26 Published since last run: 6 posts (Jun 2 – Jun 24)
27 Still scheduled: 4 posts (through Jul 6)
28 Gap starting: Jul 7
30"I'll extend from Jul 7. Same cadence, three a week?"
31```
33---

✓ Good

Open the existing calendar first, then report:
  Published since last run: 6 posts (Jun 2 – Jun 24)
  Still scheduled:          4 posts (through Jul 6)
  Gap starting:             Jul 7

"I'll extend from Jul 7. Same cadence, three a week?"

Raw lines 22 to 34
35## Gotcha: Writing a caption before reading the voice profile
37**Why it matters:** Voice fidelity is the stated adoption barrier for this
38skill. Owners do not abandon it because the graphics are wrong; they abandon
39it because the caption sounds like a brand account and not like them. The
40shared profile exists so a correction made once holds across every skill.

Gotcha: Writing a caption before reading the voice profile

Why it matters: Voice fidelity is the stated adoption barrier for this skill. Owners do not abandon it because the graphics are wrong; they abandon it because the caption sounds like a brand account and not like them. The shared profile exists so a correction made once holds across every skill.

Raw lines 35 to 41
42### ✗ Bad
44Draft 12 captions in the owner's general industry register, present them, and
45rewrite all 12 after the owner says "this doesn't sound like me."

✗ Bad

Draft 12 captions in the owner's general industry register, present them, and rewrite all 12 after the owner says "this doesn't sound like me."

Raw lines 42 to 46
47### ✓ Good
49Read `../../../shared/voice-profile.md` first. Anchor on the never-dos before
50each caption, not just the first. If no profile exists, build one from their
51own posts and confirm it before drafting at volume.
53---

✓ Good

Read ../../../shared/voice-profile.md first. Anchor on the never-dos before each caption, not just the first. If no profile exists, build one from their own posts and confirm it before drafting at volume.


Raw lines 47 to 54
55## Gotcha: Restating a Shopify price from memory
57**Why it matters:** A wrong price in a public post cannot be quietly fixed
58after a hundred people have seen it. Prices change between sessions, and the
59calendar is long-lived, so a number carried over from an earlier run is
60routinely stale.

Gotcha: Restating a Shopify price from memory

Why it matters: A wrong price in a public post cannot be quietly fixed after a hundred people have seen it. Prices change between sessions, and the calendar is long-lived, so a number carried over from an earlier run is routinely stale.

Raw lines 55 to 61
62### ✗ Bad
64"The mini-split was USD 2,400 last time we posted — I'll use that again."

✗ Bad

"The mini-split was USD 2,400 last time we posted — I'll use that again."

Raw lines 62 to 65
66### ✓ Good
68Read `variants[].price` fresh for every post that names a number. If the
69connector did not return one, say the price is unavailable and ask. Only claim
70"was X, now Y" when `compare_at_price` exists and is genuinely higher.
72---

✓ Good

Read variants[].price fresh for every post that names a number. If the connector did not return one, say the price is unavailable and ask. Only claim "was X, now Y" when compare_at_price exists and is genuinely higher.


Raw lines 66 to 73
74## Gotcha: Generating ANY Canva design for an email row
76**Why it matters:** Canva is out of scope for the email path entirely.
77Canva email-template autofill produces placeholder graphics (stock
78landscapes, blank rectangles) in service-grid tiles, and variation
79thumbnails fail to render in chat. Emails are text-only
80from this skill, period. Generating a Canva email design — even one —
81breaks that rule.

Gotcha: Generating ANY Canva design for an email row

Why it matters: Canva is out of scope for the email path entirely. Canva email-template autofill produces placeholder graphics (stock landscapes, blank rectangles) in service-grid tiles, and variation thumbnails fail to render in chat. Emails are text-only from this skill, period. Generating a Canva email design — even one — breaks that rule.

Raw lines 74 to 82
83### ✗ Bad
85```
86Calendar has 6 social rows + 2 email rows.
87→ Step 6 generates 6 social designs + 2 email designs.
88→ Email designs ship with placeholder service tiles.
89```
91Or any variation: "I'll generate the email template just to give you a
92visual reference," "I found an email template that might work, want to
93preview it?", "Here's a Canva design for the Jun 5 email…" — all
94forbidden.

✗ Bad

Calendar has 6 social rows + 2 email rows.
→ Step 6 generates 6 social designs + 2 email designs.
→ Email designs ship with placeholder service tiles.

Or any variation: "I'll generate the email template just to give you a visual reference," "I found an email template that might work, want to preview it?", "Here's a Canva design for the Jun 5 email…" — all forbidden.

Raw lines 83 to 95
96### ✓ Good
98```
99Step 2: Calendar built with Path column.
100 - 6 rows tagged Canva (social)
101 - 2 rows tagged Text-only (no Canva)
102Step 6: Generates exactly 6 Canva designs. Email rows are not passed
103 to any Canva endpoint.
104Step 8: Drafts 6 social captions + 2 full emails (subject + preheader +
105 body) as plain text.
106Step 9: Stages 6 social posts. Surfaces 2 emails inline for the owner
107 to copy into their email tool.
108```
110If the owner explicitly asks for a Canva email design ("can you make me
111a Canva version of the Jun 5 email?"), redirect: "This skill keeps emails
112as text-only because the Canva email path produces placeholder graphics.
113If you want a Canva-designed email, build it directly in Canva and I can
114help you write the copy here."
116---

✓ Good

Step 2: Calendar built with Path column.
  - 6 rows tagged Canva (social)
  - 2 rows tagged Text-only (no Canva)
Step 6: Generates exactly 6 Canva designs. Email rows are not passed
        to any Canva endpoint.
Step 8: Drafts 6 social captions + 2 full emails (subject + preheader +
        body) as plain text.
Step 9: Stages 6 social posts. Surfaces 2 emails inline for the owner
        to copy into their email tool.

If the owner explicitly asks for a Canva email design ("can you make me a Canva version of the Jun 5 email?"), redirect: "This skill keeps emails as text-only because the Canva email path produces placeholder graphics. If you want a Canva-designed email, build it directly in Canva and I can help you write the copy here."


Raw lines 96 to 117
118## Gotcha: Generating without a budget plan
120**Why it matters:** Canva caps API usage at 100 requests/minute per token,
121and each design costs ~5 calls (autofill + export + polling). A 10-row
122campaign with 4 candidates per row generates 40 designs and ~200 API
123calls — and the math gets worse with parallelism. Without a pre-flight
124budget, the owner hits quota mid-campaign with no clear recovery path
125and four already-generated posts sitting unused.

Gotcha: Generating without a budget plan

Why it matters: Canva caps API usage at 100 requests/minute per token, and each design costs ~5 calls (autofill + export + polling). A 10-row campaign with 4 candidates per row generates 40 designs and ~200 API calls — and the math gets worse with parallelism. Without a pre-flight budget, the owner hits quota mid-campaign with no clear recovery path and four already-generated posts sitting unused.

Raw lines 118 to 126
127### ✗ Bad
129```
130Calendar approved → immediately fire 4 candidates × 8 rows in parallel
131→ ~160 API calls in 90 seconds → RATE_LIMIT_EXCEEDED on post 5 → loop
132on retry → owner blocked.
133```

✗ Bad

Calendar approved → immediately fire 4 candidates × 8 rows in parallel
→ ~160 API calls in 90 seconds → RATE_LIMIT_EXCEEDED on post 5 → loop
on retry → owner blocked.
Raw lines 127 to 134
135### ✓ Good
137```
138Step 4: "8 Canva rows × 3 candidates = 24 designs, ~120 API calls.
139Proceed at default 3 candidates per row?"
141Step 6: row 1's 3 candidates fire in parallel → 30s pause → row 2 →
14230s pause → row 3 → … finishes at ~12 designs/minute, well under the
143quota.
145If quota does hit anyway: stop, surface progress, ask the owner
146whether to drop to single candidates, pause an hour, or move to
147captions with what's done.
148```
150---

✓ Good

Step 4: "8 Canva rows × 3 candidates = 24 designs, ~120 API calls.
Proceed at default 3 candidates per row?"

Step 6: row 1's 3 candidates fire in parallel → 30s pause → row 2 →
30s pause → row 3 → … finishes at ~12 designs/minute, well under the
quota.

If quota does hit anyway: stop, surface progress, ask the owner
whether to drop to single candidates, pause an hour, or move to
captions with what's done.

Raw lines 135 to 151
152## Gotcha: Skipping Checkpoint 1 (calendar approval) before generating assets
154**Why it matters:** Generating 10+ Canva designs takes API calls, time, and
155user attention. If the calendar has the wrong dates, wrong channels, or the
156owner changes their mind about a theme, all that work is discarded. The
157calendar checkpoint is the cheapest place to catch misalignment.

Gotcha: Skipping Checkpoint 1 (calendar approval) before generating assets

Why it matters: Generating 10+ Canva designs takes API calls, time, and user attention. If the calendar has the wrong dates, wrong channels, or the owner changes their mind about a theme, all that work is discarded. The calendar checkpoint is the cheapest place to catch misalignment.

Raw lines 152 to 158
159### ✗ Bad
161Receive the brief → immediately start calling `POST /autofills` for all 12
162posts → present designs before the owner has agreed on the schedule.
164Owner: "Oh wait, I didn't want any posts the week of the 15th, I'm traveling."

✗ Bad

Receive the brief → immediately start calling POST /autofills for all 12 posts → present designs before the owner has agreed on the schedule.

Owner: "Oh wait, I didn't want any posts the week of the 15th, I'm traveling."

Raw lines 159 to 165
166### ✓ Good
168Present the calendar table first. Wait for explicit "looks good" before opening
169a single Canva API call.
171---

✓ Good

Present the calendar table first. Wait for explicit "looks good" before opening a single Canva API call.


Raw lines 166 to 172
173## Gotcha: Template has more image slots than the brief provides photos for
175**Why it matters:** Multi-image social templates (Instagram carousels,
176product grids) can have 3+ image slots. When the brief gives you 1 photo
177and the template demands 3, the unfilled slots silently render Canva's
178stock landscape graphic — generic clouds and green hills where product
179photos should be. The design looks "complete" until the owner opens it.
181(Note: email rows skip Canva entirely in this skill — see SKILL.md Step 2.
182This gotcha applies only to social templates with multiple image slots.)

Gotcha: Template has more image slots than the brief provides photos for

Why it matters: Multi-image social templates (Instagram carousels, product grids) can have 3+ image slots. When the brief gives you 1 photo and the template demands 3, the unfilled slots silently render Canva's stock landscape graphic — generic clouds and green hills where product photos should be. The design looks "complete" until the owner opens it.

(Note: email rows skip Canva entirely in this skill — see SKILL.md Step 2. This gotcha applies only to social templates with multiple image slots.)

Raw lines 173 to 183
184### ✗ Bad
186Build manifest with one row per design ("Carousel — needs Hero_Image").
187Upload the one photo. Generate. Carousel ships with slide 1 populated
188and slides 2-3 both showing identical generic landscapes.

✗ Bad

Build manifest with one row per design ("Carousel — needs Hero_Image"). Upload the one photo. Generate. Carousel ships with slide 1 populated and slides 2-3 both showing identical generic landscapes.

Raw lines 184 to 189
190### ✓ Good
192Build manifest slot-by-slot. Surface the gap explicitly:
194```
195The "3-product carousel" template has 3 image slots. The brief gave me
1961 photo. How should I fill the other 2?
1981. Reuse the same photo across all 3 slots
1992. I'll send you 2 more photos
2003. Pick a single-image template
201```
203Wait for the owner's choice before generating. Don't let placeholder
204graphics ship.
206---

✓ Good

Build manifest slot-by-slot. Surface the gap explicitly:

The "3-product carousel" template has 3 image slots. The brief gave me
1 photo. How should I fill the other 2?

1. Reuse the same photo across all 3 slots
2. I'll send you 2 more photos
3. Pick a single-image template

Wait for the owner's choice before generating. Don't let placeholder graphics ship.


Raw lines 190 to 207
208## Gotcha: Trusting `status: success` without exporting and visually verifying
210**Why it matters:** A successful autofill job means Canva accepted the
211request and produced a design — not that the design contains the right
212images. If an `asset_id` was empty, stale, or wrong-typed, the job still
213returns `status: success` and the design renders with default placeholder
214graphics. The only way to know is to look at the rendered output.

Gotcha: Trusting status: success without exporting and visually verifying

Why it matters: A successful autofill job means Canva accepted the request and produced a design — not that the design contains the right images. If an asset_id was empty, stale, or wrong-typed, the job still returns status: success and the design renders with default placeholder graphics. The only way to know is to look at the rendered output.

Raw lines 208 to 215
216### ✗ Bad
218```
219Job status: success ✓
220result.design.id: present ✓
221→ Present to owner
222```
224Result: owner opens the carousel and sees stock landscape graphics in 3 of
2254 designs.

✗ Bad

Job status: success ✓
result.design.id: present ✓
→ Present to owner

Result: owner opens the carousel and sees stock landscape graphics in 3 of 4 designs.

Raw lines 216 to 226
227### ✓ Good
229After the job succeeds, export each design to a permanent PNG via
230`POST /exports` (or `export-design` MCP). Look at each PNG and confirm it
231contains real assets — not Canva's default landscape, not gray rectangles,
232not lorem-ipsum text. Only present to the owner after visual verification
233passes.
235---

✓ Good

After the job succeeds, export each design to a permanent PNG via POST /exports (or export-design MCP). Look at each PNG and confirm it contains real assets — not Canva's default landscape, not gray rectangles, not lorem-ipsum text. Only present to the owner after visual verification passes.


Raw lines 227 to 236
Uses an outside tool MCP :230
237## Gotcha: One design in a batch fails to render
239**Why it matters:** When 1 of 4 designs in a batch fails (job error, expired
240preview URL, placeholder rendered) and you present the partial carousel
241anyway, the owner sees three real designs and one "Show Image" gray
242rectangle. They lose trust in the rest of the carousel even though it's
243fine.

Gotcha: One design in a batch fails to render

Why it matters: When 1 of 4 designs in a batch fails (job error, expired preview URL, placeholder rendered) and you present the partial carousel anyway, the owner sees three real designs and one "Show Image" gray rectangle. They lose trust in the rest of the carousel even though it's fine.

Raw lines 237 to 244
245### ✗ Bad
247```
248Week 1 designs are ready:
249[Option A — real preview]
250[Option B — real preview]
251[Option C — real preview]
252[Option D — Show Image placeholder]
253Which one should I use?
254```

✗ Bad

Week 1 designs are ready:
[Option A — real preview]
[Option B — real preview]
[Option C — real preview]
[Option D — Show Image placeholder]
Which one should I use?
Raw lines 245 to 255
256### ✓ Good
258When you detect the broken design during Step 6 verification, regenerate just
259that one design with the correct asset_id. Re-export, re-verify. Only
260present once all four designs in the batch have permanent, verified
261previews. If the second attempt also fails, ask the owner whether to skip,
262swap template, or try a different photo.
264---

✓ Good

When you detect the broken design during Step 6 verification, regenerate just that one design with the correct asset_id. Re-export, re-verify. Only present once all four designs in the batch have permanent, verified previews. If the second attempt also fails, ask the owner whether to skip, swap template, or try a different photo.


Raw lines 256 to 265
266## Gotcha: Generating assets without confirming all autofill fields have values
268**Why it matters:** Canva autofill silently renders empty placeholders when a
269field value is missing or the referenced `asset_id` doesn't exist. The result
270is a professional-looking template with blank white rectangles where the
271product photo and headline should be.

Gotcha: Generating assets without confirming all autofill fields have values

Why it matters: Canva autofill silently renders empty placeholders when a field value is missing or the referenced asset_id doesn't exist. The result is a professional-looking template with blank white rectangles where the product photo and headline should be.

Raw lines 266 to 272
273### ✗ Bad
275Build calendar → immediately fire all `POST /autofills` in parallel → half
276the designs come back with empty image placeholders because product photos
277weren't uploaded first.

✗ Bad

Build calendar → immediately fire all POST /autofills in parallel → half the designs come back with empty image placeholders because product photos weren't uploaded first.

Raw lines 273 to 278
279### ✓ Good
281Build calendar → inventory every autofill field slot-by-slot → upload missing
282product images → confirm all field values with owner → then generate designs
283in parallel, with every field pre-populated.
285---

✓ Good

Build calendar → inventory every autofill field slot-by-slot → upload missing product images → confirm all field values with owner → then generate designs in parallel, with every field pre-populated.


Raw lines 279 to 286
287## Gotcha: Passing invalid values to image autofill fields
289**Why it matters:** When an autofill image field receives an empty string, a
290file path, a URL, or a stale/invalid `asset_id`, Canva does not error — it
291silently renders the template's default placeholder graphic (e.g., a generic
292landscape with clouds and hills). The design looks "finished" but the hero
293image is stock art, not the owner's product photo.

Gotcha: Passing invalid values to image autofill fields

Why it matters: When an autofill image field receives an empty string, a file path, a URL, or a stale/invalid asset_id, Canva does not error — it silently renders the template's default placeholder graphic (e.g., a generic landscape with clouds and hills). The design looks "finished" but the hero image is stock art, not the owner's product photo.

Raw lines 287 to 294
295### ✗ Bad
297Upload product photo → don't wait for the upload job to complete → pass the
298`job_id` (not the `asset.id`) into the autofill data → design renders with
299a placeholder landscape instead of the product photo.

✗ Bad

Upload product photo → don't wait for the upload job to complete → pass the job_id (not the asset.id) into the autofill data → design renders with a placeholder landscape instead of the product photo.

Raw lines 295 to 300
301### ✓ Good
303Upload product photo via `POST /v1/asset-uploads` → poll
304`GET /v1/asset-uploads/{job_id}` until `status == "success"` → extract
305`asset.id` from the response → pass that exact ID into the autofill image
306field. Verify every image field has a confirmed `asset.id` before calling
307`POST /autofills`.
309---

✓ Good

Upload product photo via POST /v1/asset-uploads → poll GET /v1/asset-uploads/{job_id} until status == "success" → extract asset.id from the response → pass that exact ID into the autofill image field. Verify every image field has a confirmed asset.id before calling POST /autofills.


Raw lines 301 to 310
311## Gotcha: Embedding Canva CDN thumbnail URLs in markdown
313**Why it matters:** Canva's autofill response returns short-lived,
314authenticated CDN URLs from `design.canva.ai`. These expire within minutes.
315If Claude embeds them as markdown images (`![](design.canva.ai/...)`), they
316render as broken "Show Image" placeholders by the time the message is shown.

Gotcha: Embedding Canva CDN thumbnail URLs in markdown

Why it matters: Canva's autofill response returns short-lived, authenticated CDN URLs from design.canva.ai. These expire within minutes. If Claude embeds them as markdown images (![](design.canva.ai/...)), they render as broken "Show Image" placeholders by the time the message is shown.

Raw lines 311 to 317
318### ✗ Bad
320Generate 8 designs → manually embed each CDN thumbnail URL in the response
321as `![Hero 1](https://design.canva.ai/xxx)` → all images show as broken
322gray placeholders because the URLs expired before render.

✗ Bad

Generate 8 designs → manually embed each CDN thumbnail URL in the response as ![Hero 1](https://design.canva.ai/xxx) → all images show as broken gray placeholders because the URLs expired before render.

Raw lines 318 to 323
324### ✓ Good
326Either let the native Cowork carousel render the tool result automatically,
327or export each design via `POST /exports` and embed the **permanent** export
328URL. As a final fallback, link to the design's permanent edit URL
329(`https://www.canva.com/d/{design_id}`). Never re-embed `design.canva.ai`
330URLs.
332---

✓ Good

Either let the native Cowork carousel render the tool result automatically, or export each design via POST /exports and embed the permanent export URL. As a final fallback, link to the design's permanent edit URL (https://www.canva.com/d/{design_id}). Never re-embed design.canva.ai URLs.


Raw lines 324 to 333
334## Gotcha: Listing designs one-by-one as individual image blocks
336**Why it matters:** When Claude lists each design as a separate block
337("Hero 1 / [image] / Hero 2 / [image]"), the images render as broken
338gray "Show Image" placeholders. Presenting all designs together in a
339single grouped batch triggers Cowork's side-by-side carousel, which
340renders correctly.

Gotcha: Listing designs one-by-one as individual image blocks

Why it matters: When Claude lists each design as a separate block ("Hero 1 / [image] / Hero 2 / [image]"), the images render as broken gray "Show Image" placeholders. Presenting all designs together in a single grouped batch triggers Cowork's side-by-side carousel, which renders correctly.

Raw lines 334 to 341
342### ✗ Bad
344```
345Hero 1 — Multi-property portfolio
346[Show Image]
347View in Canva: https://canva.com/d/xxx
349Hero 2 — Coastal market case study
350[Show Image]
351View in Canva: https://canva.com/d/yyy
352```

✗ Bad

Hero 1 — Multi-property portfolio
[Show Image]
View in Canva: https://canva.com/d/xxx

Hero 2 — Coastal market case study
[Show Image]
View in Canva: https://canva.com/d/yyy
Raw lines 342 to 353
354### ✓ Good
356Present all designs in one grouped response so they render as a
357side-by-side carousel. Below the carousel, add a single prompt:
359```
360Here are 4 hero designs for Week 1. Scroll through the carousel
361above and let me know which one to keep.
362```
364---

✓ Good

Present all designs in one grouped response so they render as a side-by-side carousel. Below the carousel, add a single prompt:

Here are 4 hero designs for Week 1. Scroll through the carousel
above and let me know which one to keep.

Raw lines 354 to 365
366## Gotcha: Generating designs sequentially instead of in parallel
368**Why it matters:** Generating designs one at a time means the owner waits
369through N round trips instead of one. Fire all generation requests within a
370batch at once and present selection after all jobs complete.

Gotcha: Generating designs sequentially instead of in parallel

Why it matters: Generating designs one at a time means the owner waits through N round trips instead of one. Fire all generation requests within a batch at once and present selection after all jobs complete.

Raw lines 366 to 371
372### ✗ Bad
374Generate design 1 → wait → show it → generate design 2 → wait → show it →
375… × 8 designs. Owner watches a slow drip for 10 minutes.

✗ Bad

Generate design 1 → wait → show it → generate design 2 → wait → show it → … × 8 designs. Owner watches a slow drip for 10 minutes.

Raw lines 372 to 376
377### ✓ Good
379Fire all designs in the current batch at once → poll all jobs concurrently →
380once all complete, export each → verify visually → then present.
382---

✓ Good

Fire all designs in the current batch at once → poll all jobs concurrently → once all complete, export each → verify visually → then present.


Raw lines 377 to 383
384## Gotcha: Auto-selecting a brand template for Pro/Teams users
386**Why it matters:** Pro/Teams users have no brand-template API access. If
387Claude guesses a template by name and generates with the wrong one, the owner
388gets designs in the wrong colors/fonts and has to redo the work in Canva
389manually.

Gotcha: Auto-selecting a brand template for Pro/Teams users

Why it matters: Pro/Teams users have no brand-template API access. If Claude guesses a template by name and generates with the wrong one, the owner gets designs in the wrong colors/fonts and has to redo the work in Canva manually.

Raw lines 384 to 390
391### ✗ Bad
393```
394Found template "Square Post - Blue". Using this for all feed posts.
395```
396…followed by 8 designs in blue when the brand is green.

✗ Bad

Found template "Square Post - Blue". Using this for all feed posts.

…followed by 8 designs in blue when the brand is green.

Raw lines 391 to 397
398### ✓ Good
400```
401I found 3 templates in your Canva library that could work for feed posts:
4021. Square Post - Blue (last edited March 2026)
4032. Summer Promo - Green (last edited April 2026)
4043. Product Feature Card (last edited Jan 2026)
406Which one should I use?
407```
409---

✓ Good

I found 3 templates in your Canva library that could work for feed posts:
1. Square Post - Blue  (last edited March 2026)
2. Summer Promo - Green  (last edited April 2026)
3. Product Feature Card  (last edited Jan 2026)

Which one should I use?

Raw lines 398 to 410
411## Gotcha: Caption voice drift across a long calendar
413**Why it matters:** When drafting 12–20 captions in one pass, the tone tends
414to drift — early captions follow the brief's voice markers, later ones slip
415into generic marketing copy. Owners notice immediately.

Gotcha: Caption voice drift across a long calendar

Why it matters: When drafting 12–20 captions in one pass, the tone tends to drift — early captions follow the brief's voice markers, later ones slip into generic marketing copy. Owners notice immediately.

Raw lines 411 to 416
417### ✗ Bad
419Post 1: "Our handmade candles are the perfect summer gift 🌿" (matches brief: "warm, conversational")
420Post 10: "Elevate your ambiance with our artisanal fragrance collection." (corporate drift)

✗ Bad

Post 1: "Our handmade candles are the perfect summer gift 🌿" (matches brief: "warm, conversational") Post 10: "Elevate your ambiance with our artisanal fragrance collection." (corporate drift)

Raw lines 417 to 421
422### ✓ Good
424Before drafting, anchor on 2–3 voice markers from the brief (e.g., "casual,
425friendly, uses light humor"). Re-read the first draft caption before writing
426each new one. If the owner flags a voice mismatch on any caption, re-read that
427caption and flag it as the recalibration point for the remaining drafts.
429---

✓ Good

Before drafting, anchor on 2–3 voice markers from the brief (e.g., "casual, friendly, uses light humor"). Re-read the first draft caption before writing each new one. If the owner flags a voice mismatch on any caption, re-read that caption and flag it as the recalibration point for the remaining drafts.


Raw lines 422 to 430
431## Gotcha: Staging HubSpot posts without verifying `scheduledAt` is in the future
433**Why it matters:** HubSpot rejects posts with `scheduledAt` in the past with
434a validation error. If the calendar was built on an earlier date and the
435owner is only now staging, some dates may have passed.

Gotcha: Staging HubSpot posts without verifying scheduledAt is in the future

Why it matters: HubSpot rejects posts with scheduledAt in the past with a validation error. If the calendar was built on an earlier date and the owner is only now staging, some dates may have passed.

Raw lines 431 to 436
437### ✗ Bad
439Build calendar on April 1st for June posts → owner approves May 15th → try to
440stage without checking → post for "April 30th 10:00 AM" returns 400.

✗ Bad

Build calendar on April 1st for June posts → owner approves May 15th → try to stage without checking → post for "April 30th 10:00 AM" returns 400.

Raw lines 437 to 441
442### ✓ Good
444Before calling `POST /social/posts`, compare each `scheduledAt` against the
445current UTC time. If any post date has passed, surface it: "The post scheduled
446for April 30th has already passed. Should I skip it, or reschedule it to next
447week?"

✓ Good

Before calling POST /social/posts, compare each scheduledAt against the current UTC time. If any post date has passed, surface it: "The post scheduled for April 30th has already passed. Should I skip it, or reschedule it to next week?"

Raw lines 442 to 447