The generation workflow ends with a thousand rows, and a thousand rows is not a plan. Left unsorted, the firehose output becomes the spreadsheet you never open again.

The fix is a four-pass system, dedupe, cluster, score, route, and it takes about ninety minutes per thousand keywords.

1,000 raw rows the firehose ~700 unique after dedupe ~60 clusters after grouping a scored queue pages, in order Each pass shrinks the object you have to think about: rows, then topics, then a queue. Ninety minutes, once per batch.
You never plan with 1,000 rows. You plan with 60 clusters wearing scores.

Pass 1: dedupe and normalize (15 minutes)

Lowercase everything, trim whitespace, remove exact duplicates. Then the near-dupes: singular/plural pairs and word-order twins ("desk standing" / "standing desk") collapse into one row each, keeping the phrasing autocomplete showed as dominant.

Do not agonize over borderline pairs here. Clustering catches whatever dedupe misses, and the goal of this pass is only to stop counting the same demand twice.

Pass 2: cluster into topics (30 minutes)

Sort alphabetically and the stems group themselves: every "sourdough starter..." row sits together, and a cluster label column fills fast.

For the scattered leftovers, use the AI sorting trick: paste them into a chat, ask for intent-labeled clusters, spot-check the result. Sorting language is the one keyword job AI does almost perfectly.

When two clusters might really be one page, apply the SERP test: search both and let Google's results draw the boundary.

Pass 3: score three columns (30 minutes)

Score clusters, not keywords: the cluster's best keyword carries its numbers. Three columns, each 1 to 3, no more precision than that.

Column3 means1 means
DemandReal volume or dense autocomplete presenceBarely typed anywhere
FitRanks would plausibly earn you moneyTraffic with no path to value
WinnabilityWeak pages rank todayGiants own every result

Multiply the three into a priority score and sort. The gut-check pass matters more than the math: any cluster whose score feels wrong gets thirty seconds of reconsideration, because the scores exist to force the argument, not to replace it.

Pass 4: route into four buckets (15 minutes)

Every cluster ends in exactly one bucket, and the buckets are the plan.

Write now: the top of the sorted list, next quarter's calendar. Improve: clusters where you already have a page that underperforms; often the fastest wins on the whole sheet. Later: real but not yet, including seasonal clusters parked until their window. Never: off-topic, unwinnable, vanity. Deleting is a feature.

The master sheet format

ColumnHolds
keywordOne phrase per row, normalized
clusterThe topic label rows share
intentlearn / compare / buy / fix
demand, fit, winThe three 1-3 scores, on the cluster
bucketnow / improve / later / never
target URLFilled when the page exists, which prevents cannibalizing later

The target URL column quietly becomes the most valuable one: a year in, it is the registry that tells you instantly whether a new idea already has a home, and it feeds the internal linking pass every new article should run.

Keep the firehose feeding it

New generation sessions append to the same sheet and ride the same four passes. The sheet is permanent; the batches flow through it.

Once a quarter, re-sort and re-bucket: rankings you gained move clusters to improve, seasons move parked ones to now, and the never bucket absorbs last quarter's optimism. Ninety minutes of sorting per thousand ideas is the price of generation actually becoming content.

The one-line takeaway: dedupe the rows, cluster the topics, score demand-fit-winnability, and route everything into now, improve, later or never. A thousand keywords is noise; sixty scored clusters with a status column is a content plan.