Show data on my TV tracker comes from TMDB, like it does for a great many TV apps. That includes the synopsis — which means the paragraph on my page for a given show is the same paragraph on TMDB itself, on JustWatch, on Trakt, and on every other app built from the same API.
Duplicate text isn't a penalty. It just can't win anything. Those are the pages meant to answer "when is the next episode of X", and the only original thing on them was my own countdown.
So: generate something. I have a machine on the LAN running a 35B model, which is more than enough to write a paragraph. The interesting part turned out to be everything I had to forbid.
The instinct is to rewrite the synopsis. Same information, different words, no longer duplicate. I didn't, for two reasons.
The first is that it lands squarely in what Google calls scaled content abuse — generating many pages without adding value. A reworded plot summary is a different arrangement of the same information: high volume, nothing new. Whether or not it trips anything, it's hard to argue you've added something the reader didn't have.
The second is simpler. Nobody searches for a synopsis. People type "is Silo weekly or all at once", "what day does Silo come out", "how many episodes in season 3". A rewritten plot summary matches none of that.
What does match it is release cadence — and cadence isn't a field. Nobody has it, because it has to be derived:
The same trick over season premieres gives "new seasons have arrived roughly every two years", which is genuinely useful and which no other TV site states.
This is the part worth copying, if anything here is: my code derives the facts, and the model is only ever asked to turn them into sentences.
It receives a small JSON object and a rule that everything in the paragraph must come from it:
If the model supplied the facts too, the failure mode would be confident invention across several hundred pages, on a site whose entire premise is telling people a date accurately. Not a risk worth taking to save writing a function.
Four failures, in the order I found them. None threw an error. Each would have been published.
It explained an internal flag, backwards. My facts included a boolean recording that TMDB stores this show's dates a day before the network advertises them — a real convention I correct for. Handed that flag, the model wrote:
New episodes are released weekly, typically arriving one day before the scheduled Thursday air date.
Which isn't what the flag means, isn't true, and is meaningless to a reader. I stopped giving it that field. Facts a model can't phrase safely don't belong in its input.
It wrote a date into text meant to last months. One note ended "…with the next installment airing tomorrow." The entire design keeps dates out of the stored text and computes them live on every render, precisely so nothing goes stale — and the model reached for "tomorrow" anyway. My validation rejected months and years. It did not reject relative time.
It described a running show as finished. Given numberOfSeasons: 4 it wrote "has completed four seasons" about a series airing its fourth. That field is how many seasons exist, not how many have ended. An easy thing for a person to misread too — but a person misreads it once, not two hundred times.
That sentence appears nowhere in its input. It came from the model's own knowledge of the show, in direct violation of an instruction telling it not to, and it reads exactly like the sentences around it that were true.
