The Generation Lane: Strategist, Writer, Visual
Three agents, three typed handoffs: quadrant demand and mined signals become a topic brief, the topic brief becomes copy, the copy becomes a format-aware asset spec. No shared blob, no guessing.
Three agents, three narrow jobs
The quadrant gate decides which quadrant is due. What happens next is the generation lane's job: turning "this quadrant is due" into an actual, publishable draft. It's tempting to build that as one agent that goes from topic idea straight to a finished asset — fewer moving parts, one prompt, one call. It's also the design that fails hardest to debug, because when the output is wrong, there's no seam to tell you whether the topic was bad, the copy was bad, or the visual assembly was bad. They were all the same undifferentiated step.
The generation lane splits that single step into three: a strategist that decides the topic, a writer that turns the topic into copy, and a visual assembler that turns the copy into a format-aware asset spec. Each agent hands the next one a typed object — a TopicBrief, then a DraftCopy — instead of a shared blob every stage can reach into. The writer never sees the grader's rubric. The strategist never sees the visual assembler's slide-count constraints. That narrowness is the entire point: when a draft comes out wrong, the typed boundary between stages tells you which stage could possibly be responsible, because each stage's inputs are exactly and only what its job requires.
Where the topic brief actually comes from
The strategist's output — the TopicBrief that kicks off the whole lane — isn't a creative guess. It's the product of merging three concrete inputs: which quadrant the gate says is due, what the mined ICP signals say people in that quadrant actually care about, and what the target format's structural rules require.
The quadrant demand comes straight from the gate built in the previous lesson — a ranked list of quadrants by priority, with the most starved quadrant carrying the highest priority. The ICP signals come from comment mining: real audience language, bucketed into pains, desires, blockers, questions, and praise, each entry weighted by how often it showed up. The format rules are structural — a carousel needs three standalone-hook slides before its payload; a reel or story needs exactly one. buildDraftBrief merges all three into a single validated object, and it's built to refuse the merge rather than paper over a gap in any of them.
That refusal matters more than it might look like at first. If the due quadrant has zero matching ICP signals — nobody's commented on anything that maps to that quadrant recently — there's no real evidence to write from. A version of this function that falls back to a different quadrant's signal, or invents a plausible-sounding topic with no signal behind it, produces a brief that looks complete and isn't. The writer downstream has no way to tell a signal-backed topic from a fabricated one; the type signature looks identical either way. The only way to keep every brief traceable back to real audience evidence is to throw at the moment the evidence doesn't exist, rather than let a topic-less brief slip through as if it were a normal one.
The cap is on the combined count, not just the extras
The one detail worth being precise about is maxTopics. It caps primaryTopic plus supportingTopics together, not supportingTopics alone — a format rule with maxTopics: 3 means one primary topic and up to two supporting ones, not one primary plus three more. Getting that boundary wrong either starves a carousel of the topic breadth it needs, or overloads a reel with more supporting material than a fifteen-second format can actually carry.
The brief is also the grader's context
Nothing about buildDraftBrief computes a score or checks quality — that's deliberately out of scope, reserved for the grader in the next lesson. But the brief this function assembles becomes part of what the grader eventually evaluates against: the on-axis check is easiest to implement correctly when the brief it's checking already carries the quadrant and the primary topic explicitly, rather than the grader having to infer intent from finished copy after the fact. Building the brief assembler carefully now means the grader inherits a clean, typed input instead of reverse-engineering what the draft was supposed to be about.
One function, three failure surfaces
It's worth naming all three ways buildDraftBrief can legitimately refuse to produce a brief, because each maps to a different upstream problem. An empty demand array means the quadrant gate never ran, or ran against a broken vault — a pipeline wiring issue. Zero matching signals for the due quadrant means comment mining hasn't surfaced anything usable yet — an upstream data problem, not a bug in this function. An unrecognized format means a caller passed a value the format rules were never configured for — a configuration problem. None of the three should be caught and swallowed at this layer; each one is more useful surfaced immediately, with its specific cause named in the thrown error, than folded into a generic failure a caller has to investigate from scratch.
This challenge is the merge step itself — the exact point where quadrant demand, mined signal, and format constraint either resolve cleanly into a brief or the function stops and says why they don't. Get it right, and every draft the writer ever touches in this operation traces back to a real, named piece of audience evidence.