A Newsroom That Runs Unattended and Publishes Nothing
A sports publisher needed coverage on a clock that never stops. We built an engine that works the clock and left exactly one human decision in place.
One Cycle, End to End
- 1
Read the signals
Live match data, the news wire, and where a fan base actually talks. The engine starts from what is happening rather than from a content calendar written last week.
- 2
Plan a slate
It decides what is worth writing right now and what kind of piece each one should be: a match report, a preview, a fan-reaction piece, a short news item. It also decides what to skip.
- 3
Write in the house voice
Against a written style specification rather than a general sense of tone, so a hundred articles read as one publication instead of a hundred different ones.
- 4
Check itself
Claims are corroborated against sources the engine actually fetches, not against memory. A piece that cannot be supported does not get emitted.
- 5
Publish to a review portal, not to the public
Everything lands in a private editorial portal. An editor reads it and decides. Nothing reaches readers on the engine's own authority.
- 6
Prove it ran
Every firing stamps a record, whatever the outcome. If the engine goes quiet, that silence raises an alarm on its own rather than being noticed a week later.
Step 5 is the design decision that matters. An autonomous writer with publish rights is a liability. An autonomous writer that fills an editor's queue multiplies what one editor can get out. The engine is fast; the judgement stays human.
The Taxonomy Is an Ontology, and It Is Enforced
Most publishing systems accumulate tags until nobody knows which are real. Here, one manifest declares how content may be categorised. Everything else reads from it: the resolver that turns a writer's raw tag into a canonical one, the dashboard filters, and the check that runs before anything ships.
Each dimension declares what kind of thing it is, whether an item can have one value or several, and what should happen when a value has never been seen before. That last column is the interesting one.
Continuous coverage means hiring for a clock that never stops, and the small hours stay uncovered anyway.
The engine works the clock and stops at an editorial queue. It holds no credential that can publish.
| Policy | When an unfamiliar value appears | Why |
|---|---|---|
| Closed | The build fails | Some sets really are finite. A match format is one of a known list, so a value outside that list means something went wrong upstream and the build should stop. |
| Curated | Accepted, and flagged for a human to confirm | Competitions and teams are real-world things somebody should name properly, but a story should never be blocked waiting for that. |
| Auto-grow | Accepted and queued, never blocked | New players appear constantly. Refusing an unknown name would stop coverage of a debut, which is exactly the story worth having. |
Scroll the table sideways →
Unknown values are always accepted and always surfaced. Coverage is never blocked by an unlisted value, and no value stays unlisted without somebody being told. One command reports what needs a human, and the strict dimensions fail loudly.
What the Manifest Declares
| Dimension | Kind | Values per article | Unknown value | Role |
|---|---|---|---|---|
| Competition | Named entity | One | Warns | The spine |
| Teams | Named entity | Several | Warns | |
| Players | Named entity | Several | Queued | |
| Format | Fixed list | One | Fails | |
| Themes | Fixed list | Several | Fails |
Scroll the table sideways →
One dimension is marked as the spine. That is the one the coverage view groups by, so the newsroom sees its output organised the way it actually thinks about the season. Everything else is a filter. Declaring which is which in the manifest means the dashboard never has to guess.
A writer types a team's short code, its nickname, or its full name. Left alone, one team becomes six categories and every count is wrong.
Every known form of a name resolves to one identity before it is stored. The variants never fragment, so a coverage report is a real number.
This is the ontology doing ordinary, load-bearing work. Nothing clever is happening. It simply cannot be skipped without every downstream count becoming fiction.
The Engine Is Not Trusted With the Keys
The machine that writes runs unattended, which means it is the least trustworthy thing in the system. It holds exactly two credentials: read access to the sport data, and permission to push its work into one repository. It holds no credential that can publish anything to the public site.
Publication happens in a separate, audited step. Tests and checks run there, and a failing check stops a bad batch before an editor ever sees it. If the writing machine were fully compromised, the worst it could do is fill a queue.
Two keys: read the sport data, push to one repository. Nothing else.
Tests, type checks and content validation. Holds the publishing credential. A failure stops here.
Reads the queue in a private portal and chooses what runs.
We decide how much damage each part could do before deciding what it may touch. The engine writes well and is trusted with almost nothing. That is why running it unattended is reasonable.
