# 04 · Validate — deterministic checks before a model ever judges the draft

**Why this step exists:** a language model grading its own draft for "no hype words" is
unreliable — it misses its own tells. A dumb, deterministic script never does. Run the cheap,
mechanical checks first; only spend a model's judgment (`05-council.md`) on the things a
script genuinely can't score (voice, structure, hook strength).

This step can be a real script (recommended — it's ~40 lines of string matching, see the
logic below) or, if you're doing this by hand, a checklist a human runs on every draft.

## Check 1 — banned-lexicon scan

Keep a short list of hype/AI-tell phrases you never want to publish. Starter list (edit it —
your ear for your own slop is better than anyone else's):

```
in today's fast-paced world
unleash
it's important to note
game-changer / game changer
dive in / dive deep
in conclusion
elevate your
supercharge
revolutionize
seamless
robust solution
at the end of the day
when it comes to
navigate the complexities
```

Scan the draft (case-insensitive) for every phrase on the list. Any hit fails the check —
report the phrase and where it landed.

## Check 2 — citation-binding

Every sentence that makes a claim needs a `[L#]` or `[FACT]` tag (from `03-draft.md`). The
mechanical rule: split the draft into sentences; a tag covers the sentence(s) before it that
share a line. Any sentence after the last tag on its line, with no tag of its own, is
"untraced" — that's a fail. (Lines that are pure hashtags or empty don't need a citation.)

Pseudocode for the citation check:

```
for each line in draft:
    if line has no citation tag and isn't a hashtag/empty line:
        split line into sentences
        find the last sentence that has a [L#] or [FACT] tag
        any sentence AFTER that one, with no tag of its own, is UNTRACED -> fail
```

## Check 3 — no em dashes

Em dashes read as an AI tell. Strip them mechanically as a final pass regardless of what the
drafting step produced — replace with a comma, a period, or an ellipsis. Do this as code, not
as an instruction to the model; a model told "don't use em dashes" still slips sometimes.

## Output

```json
{"ok": true, "banned_hits": [], "untraced": [], "traced_pct": 1.0}
```

If `ok` is false, re-prompt the drafting step ONCE with the exact offending phrases/sentences
called out, then re-validate. If it still fails, that draft needs a human, not another
automated pass.
