The craft bar every post clears, the Arabic register ladder, and the checks a draft is rejected against.

Copy

Brand says what our voice is. Strategy says what wins. This page is the craft bar — the checks a draft must clear before a human ever sees it, and the ones a human rejects it against. /draft writes to it, /carousel writes to it, /approve reads it, and the 5-minute drain reads it before it answers the first ask of the run.

It exists because the pipeline could already stop a false post and could not stop a boring one. On 2026-08-05 the unattended drain produced this, and it passed every gate the pipeline had:

القبول في مدرستك… من أول سؤال ولي الأمر إلى أول يوم للطالب. — followed by five bullets, and a trust line that was tenant scoping translated into Arabic.

One core piece, inside budget, no invented metric, no untagged link, correct Arabic. It was a summary of admission.mdx. Nothing in the pipeline was looking at whether anyone would read it.

The seven checks

Named and binary, so a skill, a reviewer, and a dismiss reason can all say "fails check 3."

1. Hook

Cover everything but the first line. Read only that. Does it name a pain the reader has felt, or a promise they want? Naming the product, the feature, or the category is a description, and a description is not a hook. Maximum 12 words. Never opens with the brand name.

  • Failsالقبول في مدرستك… من أول سؤال ولي الأمر إلى أول يوم للطالب. (a table of contents)
  • Passesأسبوع المدير يذوب في الورق. · آخر الفصل مشهد يعرفه كل معلم.

2. One idea

The piece makes one claim. Cut it at any sentence boundary — if both halves stand as posts, it is two posts. A bulleted feature list is the failure signature. Bullets are allowed only when each is a step in one process and there are three or fewer.

3. Specificity

Name the thing, not its category. القبول، الحضور، الفواتير beats العمليات الإدارية. Every abstraction is replaced with the object itself or deleted. The piece carries at least one image a person can actually see: a desk, a corridor, a stack of paper, a Thursday night.

4. Scene

Somewhere in the first third, the reader recognizes their own week. This is the check that separates copy that reads well from copy that reads like documentation — and the one the drain has never passed, structurally: product docs contain no Thursdays. If the piece was written from a feature list, it will fail here no matter how good the sentences are.

5. Sibling

Read Arabic and English side by side. If they are line-for-line parallel with the same clause order, one is a translation and the doctrine is broken. They may differ in length, in what they lead with, and in which detail they keep. Divergence in at least two places is the floor.

6. CTA

One verb, one destination, last. Never two asks. If there is a link it carries UTM (see src/lib/social-utm.tsapplyUtm runs at delivery and is idempotent). If there is no link, say what to do instead. Never both.

7. Portability

The core piece must survive any channel without editing:

  • the first line works cold — no image, no context
  • the body reads with no link preview
  • hashtags sit at the end, 3 maximum, so a channel that ignores them loses nothing
  • no platform-specific verb — no "swipe", no "link in bio", no "tap the highlight"

A piece that passes this is forwardable on WhatsApp, which Strategy names as the viral unit for Sudan. At our volume, a portable core piece is the per-channel adaptation that matters — which is why the queue lane writes one piece rather than a thin fan-out.

The reject list

Auto-fail. No discussion — and since 2026-08-06, executed rather than asserted. node scripts/social-drafts.mjs answer refuses a draft that trips any of these, naming the rule, and check runs the same gate on loose files. Since 2026-08-07 the inline Gemini lanes run it toorequestSocialDraft, refineSocialDraft, and drain-google gate every draft with one corrective retry, then refuse to the queue (the row stays pending, marked craft-refused: with the named rules, and the Mac claude lane writes fresh copy avoiding them). For a while the default lane was the one lane this page could not stop; that hole is closed.

node scripts/social-drafts.mjs check <id> --ar ar.txt --en en.txt

The rules live as data in content/social/craft-rules.json — this page's tables, in the form a machine reads — and run from src/lib/craft.ts (the app, for the review editor) and scripts/lib/craft.mjs (the CLI and the drain), pinned byte-identical by src/lib/__tests__/craft.test.ts. Edit the JSON and both change; edit this page and the JSON does not, so change them together.

What the gate can and cannot see is the thing to keep straight. It executes the list below, plus the length band, plus two failures a writer reliably misses: a number, date, or price not present in the brief (a set difference, which is what makes it the most valuable rule here), and a link without a scheme — bare ed.databayt.org parses as nothing, so applyUtm leaves it untagged and attribution silently reads zero.

It does not judge checks 1, 2, or 4. The 12-word ceiling is a floor under check 1, never the check: the 2026-08-05 draft quoted above is exactly 12 words, so it clears the rule and fails the doctrine — which is the whole reason a description is not a hook. Checks 3 and 5 only warn, because their mechanical proxies are honest but coarse. Clearing the gate is the floor, not the bar.

This is also why there is still no LLM judge (see below): the free half of that idea was always the deterministic half, and it costs no tokens on a pool that already hits session limits.

  • Opens with the brand name, نحن, or "We're excited to announce"
  • A bulleted feature list of four or more items
  • A number, name, price, or date not present in the brief
  • More than 3 hashtags — or any hashtags on Telegram, WhatsApp, or in a LinkedIn body
  • Emoji in the first line; more than one anywhere; ever as a bullet marker
  • An exclamation mark; more than one question mark
  • Engineering vocabulary carried into Arabic — نطاق المستأجر, كل قراءة وكتابة, واجهة برمجية

Length. The core piece lands at 400–900 characters of Arabic. Under 400 only for X. Over 900 means check 2 already failed and you have not noticed yet.

The Arabic register ladder

Four rungs. Rung 1 is the failure mode; rung 2 is the house default. "Correct Arabic" is not the bar — a press release is correct Arabic.

Rung 1 — فصحى الصحافة (MSA press-release). Never ships.

Markers you can point at:

  • Agentless passives where an actor exists: يتم إرسال, تم إطلاق, يُنشأ
  • Nominalized verb chains, مصدر stacking: عملية تحسين إدارة العمليات
  • Institutional self-reference: تفخر … بأن تعلن, في إطار حرصنا على, انطلاقًا من
  • Abstraction nouns with no referent: الحلول, المنظومة, التحول الرقمي, الكفاءة التشغيلية
  • Adjective pairs used for rhythm: الشامل والمتكامل, الفعّال والمرن
  • Sentences past ~20 words carrying three إضافة chains

The passive rule — the distinction that makes this operational, drawn from our own corpus:

  • الدرجة تُرصد مرة واحدةgood. The sentence is about the mark. The passive puts the subject where the reader's attention already is.
  • يُنشأ ملف الطالب وأولياء الأمر والرسوم والفواتيرbad. The reader wants to know who does this and whether it costs them anything. The passive hides exactly that.

Passive is right when the object is the topic. Passive is wrong when it hides an actor the reader is asking about.

Rung 2 — فصحى معاصرة مبسّطة. The house default.

  • Active verbs with a named actor
  • One clause per sentence; a dash or a colon carries the turn
  • Nouns the reader touches: الورق, الدفتر, الكشف, الفاتورة, المكتب, الطابور
  • Everyday verbs — يذوب, يضيع, يصل, ينتهي — not يتسنّى, يغدو, يُضحي
  • Grammatically MSA, no dialect morphology, but the rhythm of speech

This is what our shipped decks already are. It is also the only rung that reads correct to a Saudi, an Emirati, and a Sudanese reader at once — which is exactly what hogwarts needs, since its audience spans all three.

Rung 3 — عامية بيضاء (pan-Arab white colloquial).

MSA skeleton, spoken vocabulary and connectives, no morphology that marks one country. Second person (تعرف, جرّب, خليك), conversational turns (طيب, ببساطة). Consumer and short-form only.

Rung 4 — لهجة محلية.

A named local dialect. Sudanese for sijillee, per its own brand page: "a helpful neighbour who happens to be good with books." Only where a brand doc names it, only on that brand's channels.

The map

BrandChannelsRungWhy
hogwartsLinkedIn, Facebook, X2The buyer is a principal on a phone. Rung 3 reads unserious to an institution.
hogwartsInstagram, WhatsApp2, warmed — second person allowedParents. Keep MSA morphology, drop institutional distance.
mkanIG, TikTok, Snapchat, FB3Consumer, Saudi-leaning. Imagery leads; copy is short and warm.
databaytX, LinkedIn, Telegram2 in Arabic; English may run technicalDevelopers. Precision over warmth.
sijilleeFB, WhatsApp, Telegram4 — SudaneseIts brand page says so. Humility in tone; never crisis-adjacent.
moallimee2, warmedPre-launch. Locks with positioning.

Script and typography

  • Latin digits (1, 2, 3) in copy — Gulf marketing norm. Applies to captions, not just decks.
  • Diacritics only to disambiguate, never decorative — and never in a Thmanyah display headline (clearance is a known render issue; see Carousel).
  • Never letter-space Arabic. It is a connected script.
  • The brand name in Arabic prose: transliterate. في هوجورتس, not في hogwarts. Keep the Latin form for handles, links, and hashtags. A Latin token mid-sentence forces an RTL reader to context-switch, and the repo has been doing both — this line settles it.

The wordlist

Banned (AR)Use instead
الحلول · حلول متكاملةthe actual thing — نظام القبول, كشف الدرجات
المنظومةالنظام, or name the module
التحول الرقميwhat changes — من الورق إلى الشاشة
تفخر · يسرّنا أن نعلن · في إطارdelete the sentence
يتم + مصدر (يتم إرسال)the active verb — يرسل النظام
الكفاءة · الفعاليةthe time or the error actually saved
ثورة · نقلة نوعيةnothing. We cannot make that claim.
سهل الاستخدامshow it (خمس خطوات) instead of claiming it
عزيزي ولي الأمر (as an opener)speak to them, don't address them

Preferred — the register's own vocabulary, mined from the copy that works: الورق · الدفتر · الكشف · الفاتورة · الطابور · يذوب · يضيع · يُنجز · ينتهي بهدوء · أول يوم · آخر الفصل · أسبوع المدير · مرة واحدة · في مكان واحد · بلمحة · بنقرة.

Banned (EN): revolutionize · seamless · cutting-edge · empower · streamline · solutions · leverage · game-changer · "Excited to announce" · 🚀 · "workflows" (name them) · "AI-powered" unless the post is actually about the AI.

Three angles before one draft

Before writing, name three angles in one line each:

  • The pain — what the reader's week costs them
  • The moment — a scene they recognize
  • The proof — the one true fact from the brief

Pick the one whose first line survives check 1. Say in one clause why the other two lost. Then write only the winner. The runner-ups are not persisted anywhere — the discipline produces the hook; the artifact has no reader. A hand-run session says them out loud; the drain prints them to its log.

Direction: the three knobs

A brief says what the post is about. The knobs say how to write it — and they are this page's own vocabulary, so a contributor sets the same things a reviewer dismisses against.

KnobValuesUnset means
Anglepain · moment · proofThe writer runs the three-angle discipline itself
Registerrung 2 · 3 · 4Take the rung the brand + channel map above prescribes
Like this onea prior post for the same brandNo reference

Two rules make them worth having:

  • A set knob is a decision, not a hint. The writer still names three angles in its log, but it writes the one asked for. Substituting a better idea silently is how direction stops being worth giving.
  • Rung 1 is storable but never askable. The column means "a rung on the ladder"; the Hub offers 2–4, because offering the rung this page says never ships would return a draft already failed.

A reference is matched for voice — rhythm, sentence length, distance from the reader — never for subject, and its sentences are never reused. content/social/pillars.json has been encoding Angle and Register inside its brief strings since the seed lane shipped; the knobs are that convention given a home the UI can reach.

Refinement: a draft is a conversation

A draft that fails a check does not have to be dismissed and re-asked. Typing what to change in the Hub's agent window files the next turn of the same thread.

  • The parent is superseded, not overwritten — every turn keeps its own copy, its own media, and its own approvability, so a v3 that came out worse never destroys the v2 someone liked.
  • The root brief travels unchanged; the instruction rides beside it. Folding the instruction into the brief would lose the difference between what the post is about and what was wrong with the last attempt — by turn three the brief would be a changelog.
  • A refinement changes only what was asked. Keep the hook if the note is about length; keep the length if the note is about the hook. Quietly rewriting the whole post takes away the part the reviewer had already accepted, and they have to find it again.
  • Only the newest turn is answered, so the review queue shows the current draft rather than three versions of one post competing for a slot.

The reviewer's dismiss is still the feedback loop, not the quality gate — a draft that fails check 1 or check 2 is rewritten before it is answered, not after.

Why not a candidate set, an A/B, or a judge

SocialDraftRequest holds exactly one ar and one en per turn, and that is deliberate at this volume. A thread is a sequence a human steered, not a set to choose from.

  • Persisted candidates would have to ride the note field, which is rendered verbatim to the asker in the agent window — runner-ups would be invisible where they matter and corrupting where they are visible. Refinement gets the same outcome by asking, and records who asked.
  • Attribution columns (hook, pillar on a variant) need six months to hold fifty rows at ~2 posts/week — below any threshold that distinguishes a good hook from a lucky Tuesday. The strategy's stop-loss fires at 3 months on presence, not attribution. (angle became a column anyway — as an input, which needs no sample size to be useful.)
  • An LLM judge is the L4 gate, behind /decide. It costs a second model call per draft on a subscription pool that already hits session limits. The human gate exists and takes twenty seconds.

The feedback loop we run is free, and since 2026-08-06 it is actually read: dismiss reasons are stored as a structured dismissReason, and node scripts/social-drafts.mjs lessons shows the drain what reviewers rejected in the last 60 days, most common failure first — before it writes the first draft of a run. Until that column existed the reason was concatenated into a prose note where nothing could group it, and this paragraph described an intention rather than a mechanism. If "no hook" stops appearing in dismiss reasons, this page worked.

See also

  • Brand — visual identity, tone by audience, per-brand taglines
  • Strategy — the multiplier, viral mechanics, timing, the moral code
  • Carousel — the deck lane, which applies checks 1 and 2 per slide
  • .claude/skills/draft/references/golden-set.md — six annotated pairs from our own corpus