@clize/clize 0.35.5 → 0.36.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -18,7 +18,7 @@ description: >-
18
18
 
19
19
  The commands are deliberately dumb: they compress facts, they never advise. `serp` will tell
20
20
  you a page is a `listicle_window`; it will not tell you to pitch those listicles. That call is
21
- yours, and this file is how to make it.
21
+ yours.
22
22
 
23
23
  Run `clize seo <cmd> --help` for exact flags.
24
24
 
@@ -28,62 +28,55 @@ for *everyone*, so result pages are flooded with competent content and authority
28
28
  are what actually separate pages now — placement (§6) weighs more than its nominal 30%.
29
29
 
30
30
  **Three failure shapes account for most flat lines, and they need different moves.** Shape A,
31
- *no placement* (measured on our own tenant zero): nine weeks of work, on-page at 120%, live
32
- referring domains at zero, every non-brand keyword flat at position 65+ if your plan is all
33
- pages and no placement, it is that plan; the fix is §6. Shape B, *lost pages* (measured on
34
- tabledi, 2026-09): a site that *was* ranking page-1 positions with no links at all loses
35
- most of its impressions to a migration; 79 URLs returning 404 held 38% of three months'
36
- impressions, and from the keyword side the read looked exactly like Shape A. The fix is
37
- technical (restore or redirect the URLs, get them re-crawled), and links would not have moved
38
- it. The 10% is 10% of the *ceiling*; a 404 takes 100% of the *floor*. `gsc.pages` (§9) tells
39
- the two apartpages whose impressions collapsed and whose live status is not 200 are Shape B.
40
- **Do not diagnose Shape A until you have read the pages face.** Shape C, *wrong bets* (measured
41
- on our own tenant zero, 2026-09): every funded row is a head term — `stretch` / `wall`, or
42
- `attackable` on a page held by high-authority sites and not one row is a tool, a long-tail or a
43
- `no_volume` / `pre_emergence` cell. Eleven weeks, 45 pages, 0 clicks, and the only cluster with
44
- impressions was one Google picked for us. The read is `keywords.byBand` against the ledger's
45
- `format` column: if the ledger holds no row your authority can win, placement is not the fix
46
- either re-derive the ledger toward tool, long-tail and locale cells (§1.2, §7.2), building
47
- the tools if the site has none, before pitching a roundup. The counter-evidence sits in the same dogfood: tabledi and kunavo earned
48
- page-1 positions with zero links, on tool and long-tail pages. Settle it per site with one round
49
- of such rows enrolled in `check`, not by argument.
31
+ *no placement*: on-page at 120%, referring domains at zero, every non-brand keyword flat at
32
+ position 65+ (tenant zero, nine weeks) the fix is §6. Shape B, *lost pages*: a ranking site
33
+ with no links loses its impressions to a migration (tabledi, 2026-09: 79 URLs returning 404
34
+ held 38% of three months' impressions, and from the keyword side it read exactly like Shape A);
35
+ the fix is technical restore or redirect the URLs, get them re-crawled; links would not have
36
+ moved it. The 10% is 10% of the *ceiling*; a 404 takes 100% of the *floor*. `gsc.pages` (§9)
37
+ tells the two apart: impressions collapsed and live status not 200 is Shape B. **Do not
38
+ diagnose Shape A until you have read the pages face.** Shape C, *wrong bets*: every funded row
39
+ is a head term `stretch` / `wall`, or `attackable` on a page held by high-authority sites
40
+ and none is a tool, long-tail, `no_volume` or `pre_emergence` cell (tenant zero, 2026-09: 45
41
+ pages in eleven weeks, 0 clicks). Read `keywords.byBand` against the ledger's `format` column:
42
+ if the ledger holds no row your authority can win, placement is not the fix either re-derive
43
+ it toward tool, long-tail and locale cells (§1.2, §7.2), building the tools if the site has
44
+ none, before pitching a roundup. tabledi and kunavo earned page-1 positions with zero links on
45
+ tool and long-tail pages: settle it per site with one round of such rows enrolled in `check`,
46
+ not by argument.
50
47
 
51
48
  **§10 is the cycle that strings everything together. If a site exists, every session starts
52
- there — with the free entry read (`clize seo check`), not with buying data. No site yet (or
53
- nothing to point `--domain` at)? Then the cycle hasn't started: begin at §1, ship the first
54
- batch, and enter the cycle at your first enrolled check.** §1–§3 are how to run a discovery
55
- round, §4–§5 read the discovery data, §6–§7 turn rows into placement and pages, §8 is writing
56
- for AI engines, §9 reads the scoreboard. Either way, the two most common failures of this
57
- product are not misreading a number: testing a keyword set that was never enumerated (§1), and
58
- ending a session with a ledger full of buildable rows and no pages shipped (§3 test 6, §7).
49
+ there — with the free entry read (`clize seo check`), not with buying data. No site yet (nothing
50
+ to point `--domain` at)? Begin at §1, ship the first batch, and enter the cycle at your first
51
+ enrolled check.** §1–§3 run a discovery round, §4–§5 read its data, §6–§7 turn rows into
52
+ placement and pages, §8 is writing for AI engines, §9 reads the scoreboard. The two most common
53
+ failures are not misreadings of a number: testing a keyword set that was never enumerated (§1),
54
+ and ending a session with buildable rows and no pages shipped (§3 test 6, §7).
59
55
 
60
56
  ---
61
57
 
62
58
  ## 1. Where the seeds come from
63
59
 
64
- Every command except `competitors` is a **verifier**: you hand it words, it prices them. None
65
- will hand you a word you did not think of except `competitors`, and the `newQueries` that come
66
- back from `check`. The quality ceiling of the whole analysis is set before you spend a cent, by
67
- how the candidate list was built.
60
+ Every command except `competitors` is a **verifier**: you hand it words, it prices them. Only
61
+ `competitors` and `check`'s `newQueries` hand you a word you did not think of. The quality
62
+ ceiling of the analysis is set before you spend a cent, by how the candidate list was built.
68
63
 
69
64
  **Enumerate the list. Do not recall it.** A list produced by thinking hard about the product is a
70
- sample of your own memory: small, English-only, biased toward words you already believed in.
71
- Measured (kunavo, 2026-08-31): 19 recalled keywords gave six themes and zero workable rows; a
72
- 37-cell matrix the same day gave `openrouter alternative` at KD 1 with eight roundups to pitch, a
73
- German pricing cluster, a Japanese error-string query that turned out to be a UGC wall, and two
74
- payment long-tails with no recorded volume sitting at positions 4.5 and 8 in Search Console.
75
- None of those were in the 19.
65
+ sample of your own memory: small, English-only, biased toward words you already believed in
66
+ (kunavo, 2026-08-31: 19 recalled keywords gave six themes and zero workable rows; a 37-cell
67
+ matrix the same day gave `openrouter alternative` at KD 1, a German pricing cluster and two
68
+ payment long-tails already at positions 4.5 and 8 in Search Console none of them in the 19).
76
69
 
77
70
  One free source comes before the paid ones: **the entry read's own gsc face** (§10) —
78
- `gsc.topQueries` / `newQueries` are Google's list of what it already considers you relevant for.
79
- On a site with history it is the best-fitted word source there is; on a new site it is empty.
71
+ `gsc.topQueries` / `newQueries`, Google's list of what it already considers you relevant for.
72
+ The best-fitted word source there is on a site with history; empty on a new one.
80
73
 
81
74
  ### 1.1 The sweep — exhaust the competitor space once, then top it up
82
75
 
83
76
  `competitors` is the one command that hands you keywords you did not think of, and it is cheap
84
- enough to run to exhaustion — which no round had done before 2026-09-03: three sites, a dozen
85
- rivals torn down in total at `--limit 25`, ledgers of 40–60 rows on sites whose honest cell
86
- space is a few hundred. Do it once per site, and again whenever a product line is added:
77
+ enough to run to exhaustion — which no round had done before 2026-09-03 (a dozen rivals at
78
+ `--limit 25`, ledgers of 40–60 rows against cell spaces of a few hundred). Once per site, and
79
+ again whenever a product line is added:
87
80
 
88
81
  ```
89
82
  clize seo competitors a.com b.com c.com --limit 100 # one call per market: --locale
@@ -97,18 +90,18 @@ clize seo competitors a.com b.com c.com --limit 100 # one call per market
97
90
  | `seo serp` on every `attackable`, `no_volume` and `no_data` survivor (§5) | ~300 | ~$6 |
98
91
  | rows into the ledger, each with a verdict | 80–120 buildable | — |
99
92
 
100
- About $8 and one session, and the ledger goes from forty rows to a hundred-plus. Read
101
- `topKeywords[].keyword`, drop their brand terms, keep the rest. Two things the sweep is not: it
102
- is not re-run every round (the 30-day cache makes that free and pointless — top up with the new
103
- hosts each round's SERPs reveal), and it does not replace §1.2 (a rival's list is what *they*
104
- rank for; your capability cells are what *you* can serve). Expect the SERP step to kill a third
105
- to a half of the low-KD survivors — walls the difficulty score cannot see (§4): PDF→Excel at KD 0
106
- in five markets was Adobe and iLovePDF in all five. That is the funnel working, not failing.
93
+ About $8 and one session; the ledger goes from forty rows to a hundred-plus. Read
94
+ `topKeywords[].keyword`, drop their brand terms, keep the rest. The sweep is not re-run every
95
+ round (the 30-day cache makes that pointless — top up with the new hosts each round's SERPs
96
+ reveal), and it does not replace §1.2 (a rival's list is what *they* rank for; your capability
97
+ cells are what *you* can serve). Expect the SERP step to kill a third to a half of the low-KD
98
+ survivors — walls the difficulty score cannot see (§4; PDF→Excel at KD 0 was Adobe and
99
+ iLovePDF in all five markets). That is the funnel working.
107
100
 
108
101
  ### 1.2 Capability-surface enumeration — cross the axes, don't brainstorm
109
102
 
110
103
  Ask what the product can actually absorb a visitor for, find the axes of that surface, and take
111
- the cross-product. Mechanical is the point.
104
+ the cross-product.
112
105
 
113
106
  | pattern | axis A | axis B | rows you get |
114
107
  | --- | --- | --- | --- |
@@ -121,9 +114,9 @@ the cross-product. Mechanical is the point.
121
114
  | Locale × head term | your two or three head terms | each market you can serve | `de-DE` pricing cluster (price it; §7.2 on whether to build it) |
122
115
 
123
116
  - **Write every cell, then filter.** Filtering while enumerating is recalling again.
124
- - **Do the non-English cells.** They hold the low-competition rows and are the cells a recalled
125
- list always skips. Priceable markets: `en-US, en-GB, en-CA, en-AU, de-DE, fr-FR, es-ES, ja-JP,
126
- ko-KR, zh-TW, pt-BR` — anything else is a 400.
117
+ - **Do the non-English cells.** They hold the low-competition rows a recalled list always skips.
118
+ Priceable markets: `en-US, en-GB, en-CA, en-AU, de-DE, fr-FR, es-ES, ja-JP, ko-KR, zh-TW,
119
+ pt-BR` — anything else is a 400.
127
120
  - **Cells you can't serve are not candidates.** Ranking for a query you cannot answer is a bounce.
128
121
  - 30–100 cells is a normal matrix; a full site with tools, hosts and locales is 100–150. Twelve
129
122
  means you have not found your axes.
@@ -139,259 +132,235 @@ your list. No amount of enumeration produces this. Fold it back into the matrix
139
132
 
140
133
  A round is a funnel with a known size and a known price — and there is no such thing as an
141
134
  "analysis round": every round ends in pages or in a blocker the human must clear (§10).
135
+ **Two funnels, by what the cell is** (design: `seo-cell-funnel.md`). A sibling page costs
136
+ $0.01–0.05 and a SERP $0.02, so the SERP is not a gate for siblings; it is the gate for
137
+ everything that needs a brief.
142
138
 
143
139
  ```
144
- 500–1,000 candidates once (§1.1 sweep), then 30–100 a round (§1.2 matrix + top-ups)
145
- seo keywords price the whole list in one batched call
146
- drop `wall`; keep `attackable`, `no_volume` and `no_data` (§5: the SERP decides, not the volume table)
147
- → seo serp each survivor the SERP check that KD cannot replace (§4)
148
- rows written into the ledger (§3)
149
- → every buildable row shipped, family by family (§7: rows are stock, pages are output)
150
- seo check --keywords <the survivors> the baseline you measure against
140
+ A · siblings of a verified family (a tool that already earns in one market, the same tool in another)
141
+ clize seo check → cells.missing / cells.queue the product counts the family × locale grid (§7.2)
142
+ write the native phrasing the only step that is yours
143
+ clize seo check --add-keywords "<word>@<locale>#<family>" volume is fetched to order cells, never to drop one
144
+ build every queued cell; the next check binds the live page to the cell and prunes (retire / cannibal / defects)
145
+
146
+ B · a family's first page, a new page type, a head term, a commercial term, a sweep survivor
147
+ §1.1 sweep / §1.2 matrix → clize seo serp <cell> [<cell>…] batch; verdict + composition + clusters (§4)
148
+ → brief with an angle (§7.1 ①) → build → --add-keywords as above
151
149
  ```
152
150
 
153
151
  ### What it costs (measured, current version)
154
152
 
155
153
  | step | price | note |
156
154
  | --- | --- | --- |
157
- | `seo keywords`, 40 words | **~$0.10** | one batched call; per-word cost is negligible next to the fixed cost, so **always send the whole list at once** |
158
- | `seo competitors`, one domain × `--limit 100` | **~$0.04** | the cheapest words you will ever buy a 20-domain sweep is under a dollar |
159
- | `seo serp`, one keyword | **~$0.02** | every survivor gets one, `no_data` cells included — 20–100 of these is $0.40–2.00 |
155
+ | `seo keywords`, 40 words | **~$0.10** | one batched call; per-word cost is negligible, so **always send the whole list at once** |
156
+ | `seo competitors`, one domain × `--limit 100` | **~$0.04** | the cheapest words you will buy; a 20-domain sweep is under a dollar |
157
+ | `seo serp`, one keyword | **~$0.02** | every new-family survivor gets one, `no_data` included; siblings none — 20–100 of these is $0.40–2.00 |
160
158
  | `seo check` | **free**, plus ~$0.005/word to price words it has never priced | the metrics are reused for 30 days, so a re-check costs nothing |
161
159
  | `seo spend` | **free** | itemized ledger of every charge — **copy it into the deliverable, never hand-tally** |
162
160
 
163
- **The sweep is about $8, once; a round after it is about $1.** Those are the *cost priors*
164
- carry them.
161
+ **The sweep is about $8, once; a round after it is about $1; a sibling matrix is about $4, of
162
+ which the pages are $3.** Carry those *cost priors*.
165
163
 
166
- Three behaviours follow, and all matter:
164
+ What follows from them:
167
165
 
168
166
  - **Do not sample to save money.** Checking 12 of 40 keywords saves about six cents and costs
169
- you the analysis. There is no version of this work where a smaller keyword batch is the right
170
- economy. Price the whole list.
167
+ you the analysis. Price the whole list.
171
168
  - **Read the account off the receipts; never reconstruct it.** Every response's `notes[0]` is
172
169
  that call's charge in words — `this call: $0.3025 (competitors, 3 domains, limit 25, en-US)`,
173
170
  or on a cache hit `this call: $0 — cache hit (…; would cost $0.3025 fresh)`. **A cache hit is
174
- $0. Do not bill it at the fresh price**, and do not price a call from the table above — that
175
- table is a *prior for planning*, not an invoice. For the running total, `clize seo spend` is
176
- free and prints every charge itemized with subtotals by command. **Copy those numbers.** A
177
- hand-tallied total that disagrees with `seo spend` is your bug, and it is the single most
178
- common defect in these deliverables.
179
- - **You do not need a budget you need the prior.** An agent's unit of work is one batch of
180
- shipped pages the analysis is what qualifies them not one month; do not try to ration a
181
- monthly number. The `cap` block reflects this: normally
182
- it carries only `usd` (where the fuse sits). If it also carries `spentThisMonth` /
183
- `remainingUsd`, **that itself is the signal** — you are past 80% of the fuse, and a note in
184
- `notes` says so. When that happens, or whenever spend is far beyond what your session can
185
- account for at ~$1 per analysis, **stop and run `clize seo spend`** to see what actually
186
- happened (a retry loop is the usual cause) before running anything else.
187
- - **The cap is a runaway fuse, not a ration.** Default $25/month sized so normal use never
188
- touches it. Tripping it means either a runaway loop (check yourself first, see above) or
189
- genuinely heavy intentional use; for the latter, `--cap <usd>` on any `clize seo` command
190
- raises it and runs the command in one step. Passing the flag *is* the consent — no second
191
- confirmation, no support ticket. The hard limit on what you can ever spend is the account
192
- balance; the fuse blows before the balance does.
193
- - **Finish the loop.** The last step of the funnel is `seo check --keywords <survivors>`, and it
194
- is free. `seo serp` reminds you of this on every response for a reason: an analysis with no
195
- baseline cannot be compared against anything next round, so the work you just paid for only
196
- half-lands.
197
-
198
- > If you are carrying a mental model where `seo check` cost a dollar or two: that was the old
199
- > check, which scraped a full SERP for every tracked keyword every round. It doesn't any more.
200
- > Measurement is free; the exact-position scrape is now a deliberate single act (`seo serp`).
171
+ $0; never bill it at the fresh price**, and never price a call from the table above — a
172
+ *prior for planning*, not an invoice. `clize seo spend` is free and prints every charge
173
+ itemized with subtotals by command: **copy those numbers**. A hand-tallied total that disagrees
174
+ with it is your bug.
175
+ - **You do not need a budget — you need the prior.** The unit of work is one batch of shipped
176
+ pages, not one month; do not ration a monthly number. The `cap` block normally carries only
177
+ `usd` (where the fuse sits); if it also carries `spentThisMonth` / `remainingUsd`, **that
178
+ itself is the signal** — you are past 80% of the fuse, and `notes` says so. Then, or whenever
179
+ spend is far beyond ~$1 per analysis, **stop and run `clize seo spend`** (a retry loop is the
180
+ usual cause) before running anything else.
181
+ - **The cap is a runaway fuse, not a ration.** Default $25/month, sized so normal use never
182
+ touches it. Tripping it means a runaway loop (check yourself first) or genuinely heavy use;
183
+ for the latter, `--cap <usd>` on any `clize seo` command raises it and runs the command in
184
+ one step the flag *is* the consent, no second confirmation. The hard limit is the account
185
+ balance; the fuse blows first.
186
+ - **Finish the loop.** The funnel's last step, `seo check --keywords <survivors>`, is free;
187
+ `seo serp` reminds you on every response because an analysis with no baseline cannot be
188
+ compared next round.
201
189
 
202
190
  ---
203
191
 
204
192
  ## 3. The ledger
205
193
 
206
- **The worksheet is not the write-up of one analysis. It is the system state** — the ledger — and
207
- it outlives every session that touches it. One row = one bet, and the row holds the whole bet:
208
- what the world says (sv, kd, serp verdict), **what you put in** (page, placement), and why you
209
- decided what you decided. An analysis is what *writes rows*; the ledger is what *holds them
210
- between rounds*. §10's allocation step reads it, §10's last step writes it back.
211
-
212
- **Where it lives: `docs/seo/worksheet.md` in the project repo.** Not chat, not a summary, not a
213
- fresh analysis next time cross-session handoff is that file, and a new session opens it to
214
- find out where every bet stands. `check` remembers the keyword list, the brand and the GSC
215
- property; it does not remember whether you shipped the page or sent the pitch, and it never
216
- will — it cannot measure those. That half of the state exists only here.
217
-
218
- | keyword | locale | sv | kd | serp verdict | intent | target page | page | placement | format · angle | priority |
219
- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
220
- | openrouter alternative | en-US | 1,300 | 1 | listicle_window | commercial | /compare/openrouter/ | shipped:/compare/openrouter/, 08-30 | pitched: apidog roundup, 08-31 | comparison · *the only gateway that publishes its failover log* + pitch 8 roundups | P0 |
221
- | email api for ai agents | en-US | 0 (no_volume) | | listicle_window | commercial | /inbox/ | shipped:/inbox/, 08-27 | none | landing · *an inbox the agent owns, not a Gmail it borrows* + pitch 4 roundups | P0 |
222
- | メッセージストリームでエラー | ja-JP | 2,900 | 0 | definition_wall (UGC) | informational | — | none | none | skip: Reddit/Zenn own it | — |
223
-
224
- - **`target page` is the intent; `page` and `placement` are the facts.** `target page` says which
225
- page *should* carry this keyword — it is the query→page map, and §9 reads it against `check`'s
226
- `topPage`. `page` (`none` / `shipped:<url>, <date>`) and `placement` (`none` / `pitched:<target,
227
- date>` / `listed:<where>`) say what actually got funded. **You maintain those two; no command
228
- does**, and no command ever will. The date on `shipped:` is load-bearing: `check` measures a
229
- window that closes three days before you run it, and a bet placed after `rank.window.to` has
230
- not been measured by that window at all (§9, `pending`). Judging it anyway is how tabledi's
231
- 2026-09-02 round declared a P0 "missed" on a window that closed before the pages shipped.
232
- - **A row with a page and no placement is half a bet.** Building the page and not placing it is
233
- manufacturing stock and never shipping it the failure shape in the formula up top. The
234
- `placement` column is there so that half is visible at a glance instead of buried in prose.
235
- - **`target page`, `format` and the angle are part of the row.** "This keyword is good" is not
236
- a unit of work; "write /compare/openrouter/ as a comparison page and pitch these eight
237
- roundups" is and the angle (§7.1 ①) is the one line that says why that page and not a
238
- competent copy of the occupants.
239
- - **Rows you decided against stay in the table**, with the reason. That is what stops the next
240
- session from re-buying the same keywordand a `skip` row with a reason is a real finding.
241
- - **Opening the ledger on a site that already has analysis documents** (a plan, an older
242
- worksheet, a handoff note): import their skip rows and recorded lessons *before* writing a new
243
- row. A lesson you do not import is one you will re-learn at full price. tabledi, 2026-09-01,
244
- had recorded in prose that `invoice data extraction` was the site's third-best earning URL
245
- despite an enterprise-looking SERP; the next day's session opened a fresh ledger, re-derived
246
- the enterprise read from the SERP, and marked the page for retargeting. The rule that would
247
- have caught it is in §4 ("Search Console beats the SERP read"). Import **skip rows and
248
- cell-level lessons** only. Do not import site-level verdicts — "the content side has nothing
249
- left", "the bottleneck is authority" — those expire, and are re-derived every round from the
250
- cell count (§10, cadence); kunavo carried one such verdict through seven rounds, each session
251
- re-confirming it instead of counting cells. And a family described in prose is not in the
252
- ledger: a cluster, a locale axis or a page family with no rows and no `target page` will never
253
- be built — write the rows (kunavo's nine-cell integrations family sat as a paragraph for two
254
- rounds while every session executed "the existing ledger").
255
- - **Narrative goes underneath as footnotes.** Two or three lines about what the pattern means.
256
- Not six paragraphs of themes.
194
+ **The worksheet is not the write-up of one analysis. It is the system state** — the ledger —
195
+ and it outlives every session that touches it. One row = one bet, and the row holds the whole
196
+ bet: what the world says (sv, kd, serp verdict), **what you put in** (placement, angle), and why.
197
+ §10 reads it at allocation and writes it back at the end.
198
+
199
+ **Where it lives: `docs/seo/worksheet.md` in the project repo.** Not chat, not a summary:
200
+ cross-session handoff is that file, and a new session opens it to find where every bet stands.
201
+ `check` remembers the keyword list, the brand, the GSC property and the site's pages; it cannot
202
+ measure whether you sent the pitch or why you skipped a row, so that half of the state exists
203
+ only here.
204
+
205
+ | keyword | locale | family | sv | kd | serp verdict | intent | placement | format · angle | priority |
206
+ | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
207
+ | openrouter alternative | en-US | openrouter | 1,300 | 1 | listicle_window | commercial | pitched: apidog roundup, 08-31 | comparison · *the only gateway that publishes its failover log* + pitch 8 roundups | P0 |
208
+ | email api for ai agents | en-US | inbox | 0 (no_volume) | | listicle_window | commercial | none | landing · *an inbox the agent owns, not a Gmail it borrows* + pitch 4 roundups | P0 |
209
+ | csv 分割 | ja-JP | split-csv | 170 | 0 | (sibling family earns in en-US) | tool | none | tool · Shift-JIS kept, header in every part | P1 |
210
+ | メッセージストリームでエラー | ja-JP | — | 2,900 | 0 | definition_wall (UGC) | informational | none | skip: Reddit/Zenn own it | — |
211
+
212
+ - **`family` is the cell key; page state is read, never written.** Whether the page for
213
+ (family, locale) exists, is indexed, earns, or should be retired comes from `check.cells`
214
+ (§9) the product records pages as assets from the sitemap or the deploy plan. The ledger
215
+ holds what the product cannot measure: angle, priority, placement, the reason for a skip.
216
+ `placement` (`none` / `pitched:<target, date>` / `listed:<where>`) is yours to maintain.
217
+ - **A cell with a page and no placement is half a bet** (Shape A, top of this file).
218
+ - **`format` and the angle are part of the row.** "This keyword is good" is not a unit of work;
219
+ "write /compare/openrouter/ as a comparison page and pitch these eight roundups" is and the
220
+ angle (§7.1 ①) says why that page and not a competent copy of the occupants. Siblings inherit
221
+ the family's angle and change terminology and FAQ only.
222
+ - **Rows you decided against stay in the table**, with the reason that stops the next session
223
+ re-buying the same keyword, and a `skip` row with a reason is a real finding.
224
+ - **Opening the ledger on a site that already has analysis documents**: import their skip rows and
225
+ cell-level lessons *before* writing a new row a lesson you do not import is re-learned at full
226
+ price (tabledi, 2026-09-01: a page recorded in prose as the site's third-best earner was re-marked
227
+ for retargeting the next day; §4 catches it). Do not import site-level verdicts "the content
228
+ side has nothing left", "the bottleneck is authority" those expire and are re-derived each round
229
+ from the cell count (§10, cadence; kunavo re-confirmed one through seven rounds instead of
230
+ counting cells). A family described in prose is not in the ledger and will never be built: write
231
+ the rows, or enroll the cells with `--add-keywords` (kunavo's nine-cell integrations family sat as
232
+ a paragraph for two rounds).
233
+ - **Narrative goes underneath as footnotes.** Two or three lines on what the pattern means, not
234
+ six paragraphs of themes.
257
235
  - **Every ledger file counts, and a plan is a queue.** A site may carry more than one ledger
258
- (tabledi: `worksheet.md` for en-US and `worksheet-global.md` for the other markets); rows in
259
- all of them are the site's rows, and a round that counts only one file will report "nothing
260
- to build" beside the cells the other file already verified. A batch plan written under an earlier count rule (`≤5,
261
- wait for impressions`) is not re-planned and never "the next batch": each cell is re-gated
262
- on its own SERP verdict, and every cell that passes is a `to build` row for step ⓪ of the
263
- next session (§10). tabledi's B1–B4 sat under "next batch" through three sessions and when a
264
- session finally counted, only 15 of its cells had a SERP and 6 of those were unbuilt: a plan
265
- is not a verified list until each cell has its own verdict; buy the missing ones ($0.02 each)
266
- in the same session, never "next time".
267
-
268
- **Page batches the second table in the ledger.** Keyword rows hold bets; the batch table holds
269
- what the site's composition is doing, and it is what the batch gate and the retire rule (§7.3)
270
- run on. One row per shipped batch, updated at every check from `gsc.pages`:
236
+ (tabledi: `worksheet.md` for en-US, `worksheet-global.md` for the rest); rows in all of them
237
+ are the site's rows, and `check.cells` counts pages whichever file the row sits in. A batch
238
+ plan written under an earlier count rule (`≤5, wait for impressions`) is not re-planned and
239
+ never "the next batch": each cell is re-gated under gate 1 (§7.3), and every cell that passes
240
+ is a `to build` row for step ⓪ of the next session (§10; tabledi's B1–B4 sat under "next
241
+ batch" through three sessions when counted, 15 cells had a SERP and 6 were unbuilt). A new
242
+ family's one SERP ($0.02) is bought in the same session, never "next time"; a verified
243
+ family's siblings need none.
244
+
245
+ **Page batches — the second table in the ledger.** What the site's composition is doing — what
246
+ the batch gate and retire rule (§7.3) run on. One row per shipped batch, updated at every check
247
+ from `gsc.pages` and `cells`:
271
248
 
272
249
  | batch | shipped | pages | indexed | not indexed | zero-impression windows | retired |
273
250
  | --- | --- | --- | --- | --- | --- | --- |
274
251
  | seo-tools-1 — llms.txt / hreflang / faq × en+de+ja | 2026-09-02 | 7 | 0 | 7 | 0 | 0 |
275
252
 
276
- `indexed` / `not indexed` come from `gsc.pages.unseen[].index` (and from `latest` once a page
277
- earns impressions); `zero-impression windows` counts the full windows since shipping in which the
278
- batch earned nothing; `retired` counts pages noindexed, merged or redirected under §7.3. A batch
279
- is found by `firstSeen` on the unseen rows — the date `check` first saw those URLs in the
280
- sitemap — and `unseenTotal` says how much of the site the list is showing you.
253
+ `indexed` / `not indexed` come from `gsc.pages.unseen[].index` (and `latest` once a page earns);
254
+ `zero-impression windows` counts full windows since shipping in which the batch earned nothing
255
+ (`cells.retire` lists the pages that have reached two); `retired` counts pages noindexed,
256
+ merged or redirected under §7.3. A batch is found by `firstSeen` on the unseen rows, and
257
+ `unseenTotal` says how much of the site the list is showing you.
281
258
 
282
259
  ### The pass/fail test
283
260
 
284
- Six ways a round fails. The first is about *what you found*, the last two about *what you
285
- funded*; the middle three are about *whether you actually ran the analysis you claim to have
286
- run* all six have been observed in real runs that read as finished.
287
-
288
- 1. **Themes instead of rows.** If what you produced is a set of *directions* or *themes*, or
289
- the table has fewer than ten actionable rows, **the fix is upstream, in §1**. Do not write it
290
- up. Go back and enumerate more cells. This is exactly what happened in round one of the
291
- kunavo dogfood: six well-argued themes, and not one row anybody could start on.
292
- 2. **You priced fewer keywords than you enumerated, with no recorded rule for the gap.** If the
293
- candidate matrix had 225 cells and you bought 36, the analysis is not "focused", it is
294
- sampled and the rows you did not buy are exactly where the cheap wins were 1). The only
295
- legitimate way to shrink the list before spending is a **zero-cost rule written into the
296
- deliverable** ("dropped 14 pure-brand queries for competitors' own names"), which is a filter
297
- anyone can re-derive. "To save money" is not such a rule: the whole 225 would have cost about
298
- what a sampled 36 does plus a quarter (§2).
299
- 3. **The money in the write-up does not match `seo spend`.** Sub-totals that don't add to the
300
- total, or a cache hit billed at its fresh price, means the account was reconstructed from
301
- memory instead of read off the receipts. Run `clize seo spend` (free) and copy it.
302
- 4. **No baseline.** If you never ran `seo check --keywords <survivors>`, the analysis is not
303
- finished you have a list of bets and no scoreboard, and next round has nothing to compare
304
- against. It is free. Run it before you write the summary.
305
- 5. **P0 pages with no placement rows.** If the worksheet funds pages but not one pitch,
306
- submission, or participation action beside them, the plan is the tenant-zero failure shape
307
- (on-page at 120%, links at zero see the formula up top) written down in advance. The
308
- targets are already in the serp data you paid for `parasiteTargets`, the directories and
309
- discussions visible in `items` so this costs nothing to fix: write them as rows next to
310
- the pages they support. Observed in the field (2026-08-31 second run): five funded pages,
311
- placement nearly invisible in the deliverable.
312
- 6. **Rows without pages — and families without rows.** Buildable rows — a serp verdict that is
313
- not a wall, an intent you can serve — left unshipped at session end, or handed to "next
314
- round" without one of the three blockers in §10 ⑤, are stock, not output.
315
- An opportunity written in prose (a cluster, a family, a locale axis) with no rows behind it
316
- is test 1 wearing a different coat. The deliverable counts shipped
317
- URLs, not qualified rows; a ledger of twenty rows and two pages is a session that spent itself
318
- on the analysis. Observed on kunavo: five rounds, five pages, three of the rounds at zero; and on clize.ai
319
- the opposite failure — eleven weeks in which no round ran at all. If a page costs a session, the first deliverable is the generator (§7).
261
+ Seven ways a round fails.
262
+
263
+ 1. **Themes instead of rows.** A set of *directions* or *themes*, or a table with fewer than ten
264
+ actionable rows: **the fix is upstream, in §1** — enumerate more cells, do not write it up
265
+ (kunavo round one, 2026-08-31: six well-argued themes, not one row anybody could start on).
266
+ 2. **You priced fewer keywords than you enumerated, with no recorded rule for the gap.** A
267
+ 225-cell matrix of which you bought 36 is sampled, not "focused" and the rows you did not
268
+ buy are where the cheap wins were (§1). The only legitimate shrink before spending is a
269
+ **zero-cost rule written into the deliverable** ("dropped 14 pure-brand queries for
270
+ competitors' own names") that anyone can re-derive; "to save money" is not one the whole
271
+ 225 costs about what a sampled 36 does plus a quarter2).
272
+ 3. **The money in the write-up does not match `seo spend`.** Sub-totals that don't add up, or a
273
+ cache hit billed fresh, mean the account was reconstructed instead of read off the receipts
274
+ (§2). Run `clize seo spend` and copy it.
275
+ 4. **No baseline.** Without `seo check --keywords <survivors>` you have bets and no scoreboard.
276
+ It is free; run it before the summary.
277
+ 5. **P0 pages with no placement rows.** Pages funded with no pitch, submission or participation
278
+ action beside them is Shape A written down in advance. The targets are already in the serp
279
+ data you paid for `parasiteTargets`, the directories and discussions in `items` so write
280
+ them as rows next to the pages they support (2026-08-31: five funded pages, placement nearly
281
+ invisible).
282
+ 6. **Rows without pages and families without rows.** Buildable rows a verdict that is not a
283
+ wall, an intent you can serve left unshipped at session end, or handed to "next round"
284
+ without one of the three blockers in §10 ⑤, are stock, not output; an opportunity in prose
285
+ (a cluster, a family, a locale axis) with no rows behind it is test 1 in a different coat.
286
+ The deliverable counts shipped URLs, not qualified rows (kunavo: five rounds, five pages,
287
+ three at zero; clize.ai: eleven weeks with no round). If a page costs a
288
+ session, the first deliverable is the generator (§7).
320
289
  7. **Pages without a brief.** A page whose row names no occupant gap and no product asset is a
321
- competent copy of the top 10, and at zero authority a competent copy does not rank: kunavo's
322
- five model spec pages, built from the query alone against a page of opinion pieces, read zero
323
- for three to eight weeks. The brief (§7.1 ①) is written before the page, and its angle sits in
324
- the ledger row; no angle, no page.
290
+ competent copy of the top 10, and at zero authority that does not rank (kunavo's five model
291
+ spec pages, built from the query alone, read zero for three to eight weeks). The brief
292
+ (§7.1 ①) comes before the page and its angle sits in the row; no angle, no page.
325
293
 
326
294
  ---
327
295
 
328
296
  ## 4. Reading a results page (`seo serp`)
329
297
 
330
- `verdict` compresses **who occupies the page**. Four values, and what each one means for
331
- whether you can get in:
298
+ `verdict` compresses **who occupies the page**. Five values, and what each means for whether
299
+ you can get in:
332
300
 
333
301
  | verdict | what it means | what it implies |
334
302
  | --- | --- | --- |
335
- | `official_wall` | The brand named in the query owns ≥3 of the top 5 | You are not getting in on this query. It is a navigational query wearing a category costume. |
336
- | `definition_wall` | Big vendors / encyclopedias hold ≥4 of the top 10 with "what is X" content | Do not write another definition. Go long-tail, or go where the discussion is (Reddit, HN). |
337
- | `listicle_window` | Roundups hold ≥3 of the top 10 | **The only shape you can enter without authority.** `parasiteTargets` lists the roundups — getting included in one is cheaper than outranking them. |
338
- | `open` | No single occupancy pattern the classifier can identify | **Not the same as "there's room."** Read `items` yourself. |
339
-
340
- ### `open` is the one that will fool you
341
-
342
- `open` means *the machine found no mechanical pattern*, not *the page is winnable*. Measured
343
- case: `agentic payments` came back `open`, but the top eight were ACI Worldwide, AWS,
344
- Fireblocks, Accenture, Mastercard and Kearney an enterprise definition wall in everything
345
- but the classifier's domain list. Whenever you see `open`, read the hosts. If they are all
346
- large vendors publishing thought-leadership, treat it as `definition_wall`.
303
+ | `official_wall` | The brand named in the query owns ≥3 of the top 5 | A navigational query in a category costume; you are not getting in |
304
+ | `definition_wall` | Big vendors / encyclopedias hold ≥4 of the top 10 with "what is X" content | Do not write another definition. Go long-tail, or go where the discussion is (Reddit, HN) |
305
+ | `listicle_window` | Roundups hold ≥3 of the top 10 | **The only shape you can enter without authority.** `parasiteTargets` lists the roundups — inclusion is cheaper than outranking them |
306
+ | `tool_window` | Tool pages hold ≥3 of the top 10 | A tool page can enter; the angle is what the occupant tools do not do (nothing uploaded, locale-aware text handling) |
307
+ | `open` | No single occupancy pattern the classifier can identify | Read `composition` — it is never a blind box any more |
308
+
309
+ ### Read `composition`, then `items`
310
+
311
+ Every SERP carries `composition`: the top 10 counted by kind `tool`, `tutorial`, `ugc`,
312
+ `listicle`, `reference`, `docs`, `directory`, `template`, `app`, `other` with per-market
313
+ lexicons. `open` with `{tutorial: 6, ugc: 3}` is a tutorial field a tool page can enter
314
+ (tabledi's Japanese dedupe won one); `open` with reference and consulting hosts on top is a
315
+ definition wall in everything but the label; `template` on top is download intent, not tool
316
+ intent. Intent is still yours: the classifier does not know that `두 리스트 비교` is a Python
317
+ question, but its `ugc`/`tutorial` hosts and titles put that in front of you.
347
318
 
348
319
  ### KD and the SERP are different questions — check both
349
320
 
350
- `seo keywords` says `stripe mcp server` is KD 4, `band: attackable`. `seo serp` on the same
351
- keyword returns `official_wall`: three of the top five are Stripe's own properties. **A low
352
- difficulty score on a page nobody can enter is not an opportunity.** Never pick keywords from
353
- `band` alone; run `serp` on anything you are about to invest a page in.
321
+ `seo keywords` says `stripe mcp server` is KD 4, `band: attackable`; `seo serp` on it returns
322
+ `official_wall` three of the top five are Stripe's own properties. **A low difficulty score
323
+ on a page nobody can enter is not an opportunity.** Never pick keywords from `band` alone; run
324
+ `serp` on any new family before investing a page in it (siblings inherit the verdict, §7.3).
354
325
 
355
326
  The reverse trap is just as expensive: a Japanese error-message query at 2,900/month and KD 0
356
- looks like a gift until `serp` shows the page is wall-to-wall Reddit, Zenn and Qiita threads.
357
- High volume plus zero difficulty plus a pure-UGC page means *the demand is real and it is not
358
- available to you*.
327
+ looks like a gift until `serp` shows wall-to-wall Reddit, Zenn and Qiita threads. High volume,
328
+ zero difficulty and a pure-UGC page means *the demand is real and not available to you*.
359
329
 
360
330
  ### The classifier does not judge intent — you do
361
331
 
362
- `ai agent deployment` returns `open`. Read the items and you find they are all about deploying
363
- *agent runtimes*, not about agents deploying *websites*. That is an intent mismatch, and it is
364
- invisible to a rule engine because it requires knowing what your product is. Same for
365
- `ai domain registration`, which turns out to mean "buy a .ai domain". **Always read `items`
366
- before committing to a keyword**, whatever the verdict says.
332
+ `ai agent deployment` returns `open`, but its items are about deploying *agent runtimes*, not
333
+ agents deploying *websites* an intent mismatch a rule engine cannot see, because it requires
334
+ knowing your product; `ai domain registration` likewise means "buy a .ai domain". **Always read
335
+ `items` before committing to a keyword**, whatever the verdict says.
367
336
 
368
337
  ### Search Console beats the SERP read
369
338
 
370
339
  The SERP shows who Google ranks first; Search Console shows which queries Google already sends
371
- to *your* page. When they disagree about intent, Search Console is the fact about you. So: **a
340
+ to *your* page. When they disagree about intent, Search Console is the fact about you: **a
372
341
  keyword your site already earns impressions or clicks on is never an intent-mismatch skip and
373
342
  never a retarget**, whatever the top 10 looks like. The move on such a row is additive — a
374
- section that answers the query, internal links into the page — and it keeps the title and H1
375
- that earned the impressions. tabledi, 2026-09: `invoice data extraction` read as an enterprise
376
- AP wall from the SERP (nanonets, klippa, rossum), while the page was the site's third-best
377
- earner and its "…to excel" long-tails sat at position 11. Retargeting it would have traded a
378
- measured 262 impressions for a guess. The intent-mismatch rule above is for keywords you have
379
- not entered yet; once Google has put you on a query, it has already answered the intent question.
343
+ section that answers the query, internal links into the page — keeping the title and H1 that
344
+ earned the impressions (tabledi, 2026-09: `invoice data extraction` read as an enterprise wall
345
+ from the SERP while the page was the site's third-best earner at 262 impressions). The
346
+ intent-mismatch rule is for keywords you have not entered yet; once Google has put you on a
347
+ query, it has answered the intent question.
380
348
 
381
349
  ### `aiOverview: true`
382
350
 
383
- An AI Overview sits above the organic results and answers the query in place. Position 3 under
384
- an AI Overview is worth much less than position 3 without one, and some of your impressions will
385
- never become clicks no matter what you do. Note it, factor it into expectations, and lean harder
386
- on being *quotable* (§8) than on being *ranked*.
351
+ An AI Overview answers the query above the organic results. Position 3 under one is worth much
352
+ less than position 3 without, and some impressions will never become clicks. Note it, factor it
353
+ into expectations, and lean harder on being *quotable* (§8) than on being *ranked*.
387
354
 
388
355
  ### One page or two?
389
356
 
390
- Two sibling keywords and you can't tell whether they deserve separate pages: run `serp` on
391
- both and count the URLs shared by the two top-10s. **Five or more shared → one page targeting
392
- both; fewer two pages.** Two serp calls cost $0.04 cheaper than a cannibalizing or wasted
393
- page. This is a set operation on data you were buying anyway; there is no command for it on
394
- purpose.
357
+ Two rules, by tier. **Same family, same market: one page** the second phrasing is a second
358
+ keyword on the same page (`--add-keywords "<word>@<locale>#<family>"` attaches it; the product
359
+ never makes a second page). **Two candidates that may or may not be one intent: read the
360
+ `cluster`** a batch `serp` returns same-market cells whose top-10 share ≥5 URLs are one page
361
+ in the occupants' eyes (fr *comparer deux tableaux* / *deux feuilles* shared 5: one page;
362
+ ko *파일 비교* / *시트 비교* shared 3: two). The product gives the shared count; the intent call
363
+ is yours. Siblings inherit the verified market's structure; `cells.cannibal` corrects them later.
395
364
 
396
365
  ---
397
366
 
@@ -409,55 +378,32 @@ For a site with near-zero authority (new domain, few referring domains):
409
378
 
410
379
  **Within the same band, intent ranks before volume — until the site's own clicks say
411
380
  otherwise.** Commercial rows (`<rival> alternative`, `X vs Y`, `pricing`, `best X for Y`)
412
- outrank informational rows (`what is X`) for priority: they sit at the bottom of the funnel,
413
- they convert, and conversion evidence is what justifies funding the next batch of pages. Fill
414
- the worksheet's `priority` column by intent first, volume second a KD 8 commercial row beats
415
- a KD 5 informational row. That is the prior for a site with no history. A site with history
416
- overrules it: read `gsc.pages.latest` (§9) and rank the intents that already earn clicks first.
417
- tabledi's history was 105 of 134 clicks from free tool and how-to pages and zero from anything
418
- commercial — on that site a tool-intent row outranks a `best X` row, whatever the generic rule
419
- says.
420
-
421
- ### `no_data` and `no_volume` mean opposite things
422
-
423
- They used to be one value. They are not one thing:
424
-
425
- - **`no_data`**we have no volume figure for this keyword. Either it was never priced, or it
426
- was priced and the upstream has no row for it. It is an **absence of data** and it says
427
- nothing whatsoever about demand. Never report it as "nobody searches for this."
428
- - **`no_volume`** — it *was* priced and the volume really is 0. That is a **signal**, and often
429
- a valuable one: a keyword the tools have not caught up with. `email api for ai agents` had no
430
- volume and a `listicle_window` with four roundups on it. On kunavo, two payment long-tails
431
- came back at volume 0 and Search Console showed them at positions 4.5 and 8 with real
432
- impressions — **people were already arriving on words the keyword tool scored as empty.**
433
- That configuration has a name in `check` output: `pre_emergence` (§9) — and since 0.34.0 the
434
- same label fires when the window's impressions reach twice the priced monthly volume, because
435
- a small `sv` next to a large impression count is the same fact (the tool has not caught up,
436
- or it priced one market while Search Console counts all of them). Either way, the impressions
437
- are the demand; the `sv` is not a reason to downgrade the row.
438
-
439
- So: a `no_volume` row whose SERP is already full of category roundups is worth an early page.
440
- A `no_data` row goes to `seo serp` like any other survivor — the SERP does not need a volume
441
- figure to show who occupies it. Open and servable → buildable, enrolled as `pending`; wall →
442
- skip row with the reason. What `no_data` never is: a reason to drop the cell. Measured across
443
- three sites: the demand the table could not see was real (clize.ai's German MCP cluster,
444
- `no_data` in the table, 130 impressions in Search Console), and the only page-1 positions any
445
- of the sites hold are on such cells (kunavo's payment long-tails at 4.5 and 5.8), while the
446
- priced `attackable` rows sat at 65+ or unseen — the table's coverage and the incumbents'
447
- coverage are the same coverage. On 2026-09-02, 82 of 119 cells left the funnel at
448
- the pricing step without a single SERP look; keeping them would have cost $1.64 in serp calls.
381
+ outrank informational rows (`what is X`): they sit at the bottom of the funnel, they convert,
382
+ and conversion evidence funds the next batch. Fill `priority` by intent first, volume second —
383
+ a KD 8 commercial row beats a KD 5 informational row. That is the prior for a site with no
384
+ history; a site with history overrules it read `gsc.pages.latest` (§9) and rank the intents
385
+ that already earn clicks first (tabledi: 105 of 134 clicks from tool and how-to pages, zero
386
+ from anything commercial).
387
+
388
+ ### `no_data` and `no_volume` mean opposite things — and neither drops a cell
389
+
390
+ `no_data` is an absence of data (no upstream row); `no_volume` is a priced 0. Both were the
391
+ cells the page-1 wins came from on three sites (kunavo's payment long-tails at 4.5 and 5.8,
392
+ clize.ai's German MCP cluster at 130 impressions). **Volume orders cells; it never removes one.**
393
+ A sibling with `no_data` is built like any other; a `no_data` head term goes to `serp` like any
394
+ other survivorthe `keywords` receipt's last line says which. `check` labels the configuration
395
+ when it appears: `pre_emergence` (§9).
449
396
 
450
397
  ### `--ai` is a different unit
451
398
 
452
- `--ai` adds `aiSv`, the volume inside AI engines. **It is a different unit from `sv`.** Measured:
453
- `agent mail` is 5,400 on Google and 125 in AI engines; `ai email agent` is 140 and 5. Compare a
454
- keyword to itself over time, or rank keywords against each other — never put `sv` and `aiSv` in
455
- the same sentence as if they were the same quantity, and never add them.
399
+ `--ai` adds `aiSv`, the volume inside AI engines. **It is a different unit from `sv`**
400
+ (`agent mail`: 5,400 on Google, 125 in AI engines; `ai email agent`: 140 and 5). Compare a
401
+ keyword to itself over time, or rank keywords against each other — never treat `sv` and
402
+ `aiSv` as the same quantity, and never add them.
456
403
 
457
- One locale carries its own unit caveat: **ko-KR volumes are Google-side only**, and in Korea
458
- Naver holds the majority of search — read Korean `sv` as a floor, not the market. (Simplified
459
- Chinese is not in the locale list at all: Baidu is a different data ecosystem the product
460
- honestly does not measure.)
404
+ One locale carries its own caveat: **ko-KR volumes are Google-side only**, and in Korea Naver
405
+ holds the majority of search — read Korean `sv` as a floor, not the market. Simplified Chinese
406
+ is not in the locale list at all: Baidu is a data ecosystem the product does not measure.
461
407
 
462
408
  ---
463
409
 
@@ -466,55 +412,52 @@ honestly does not measure.)
466
412
  Priority order, most effective first for a low-authority site:
467
413
 
468
414
  1. **Third-party trust positions.** Registries and directories that accept submissions, and the
469
- roundups in `parasiteTargets`. Getting listed in a page that already ranks beats trying to
470
- outrank it. Each target carries `owner`: `publisher` (independent media, review or directory
471
- site — pitch first), `unknown` (go look at who runs it), `vendor` (the host sells in this
472
- category, or the roundup sits under a product site's `/blog/`-type path — pitch last, and
473
- only if what you sell is not what they sell). A vendor's roundup of its own category rarely
474
- adds a rival and never adds a product from another category: tabledi's five `client reporting
475
- tool` targets were all vendor blogs, with zero fit for a desktop spreadsheet, and were queued
476
- as P0 placement anyway. **If every target is `vendor`, the `listicle_window` is narrower than
477
- the verdict says** treat it as one or two pitches, not a placement plan. Directory/forum
478
- submissions stay manual the product produces the target list,
479
- it does not post anything. One class is manual **once**, not per-post: platforms with a
480
- publish API (dev.to, Hashnode) need a human to create the account and mint an API key one
481
- time; after that the agent drafts, sets `canonical_url` back to your own page (skip it and
482
- you are competing with yourself), and pushes each post as a draft over the API for a human
483
- glance-and-publish. A ready draft waiting on "no account yet" for weeks is the failure mode
484
- this avoids. The *email* half of outreach is different: see §6.2.
485
- 2. **Where the discussion already is.** Reddit and HN rank on a large share of these queries
486
- (they appear in nearly every SERP fixture we have). Participating is legitimate; astroturfing
487
- is not, and it will cost you the account and the credibility.
488
- 3. **Your own site last.** Not because it doesn't matter, but because on a new domain it is the
489
- slowest of the three. Publish there, then go get the first two.
415
+ roundups in `parasiteTargets`: getting listed in a page that already ranks beats outranking
416
+ it. Each target carries `owner`: `publisher` (independent media, review or directory site —
417
+ pitch first), `unknown` (go look at who runs it), `vendor` (the host sells in this category,
418
+ or the roundup sits under a product site's `/blog/`-type path — pitch last, and only if what
419
+ you sell is not what they sell; a vendor's roundup of its own category rarely adds a rival
420
+ and never a product from another category tabledi's five `client reporting tool` targets
421
+ were all vendor blogs with zero fit, queued as P0 placement anyway). **If every target is
422
+ `vendor`, the `listicle_window` is narrower than the verdict says** — one or two pitches, not
423
+ a placement plan. Directory/forum submissions stay manual the product produces the target
424
+ list, it does not post. Platforms with a publish API (dev.to, Hashnode) are manual **once**:
425
+ a human creates the account and mints an API key; after that the agent drafts, sets
426
+ `canonical_url` back to your own page (skip it and you compete with yourself), and pushes
427
+ each post as a draft for a human glance-and-publish. The *email* half of outreach: §6.2.
428
+ 2. **Where the discussion already is.** Reddit and HN rank on a large share of these queries.
429
+ Participating is legitimate; astroturfing is not, and it
430
+ will cost you the account and the credibility.
431
+ 3. **Your own site last.** On a new domain it is the slowest of the three. Publish there, then
432
+ go get the first two.
490
433
 
491
434
  ### 6.1 Link strategies an agent can actually run
492
435
 
493
436
  Links are the ~30% (see the formula up top) and the part agents historically skip. Of the
494
- classic white-hat playbook, these survive the cut — each one either produces the asset or
495
- produces the target list, with a human approving anything that leaves the building:
437
+ classic white-hat playbook, these survive — each produces the asset or the target list, with a
438
+ human approving anything that leaves the building:
496
439
 
497
440
  - **Statistics / first-party-data articles.** Publish numbers nobody else has (your own measured
498
- data). Ranked stats pages attract citations on their own. Cheapest durable link magnet.
441
+ data); ranked stats pages attract citations on their own. Cheapest durable link magnet.
499
442
  - **Free tool pages** (§7.2). A tool that ranks becomes a link magnet without outreach.
500
443
  - **Parasite pitches.** `serp` hands you `parasiteTargets` — roundups already ranking on your
501
- keyword. Getting added to one beats months of trying to outrank it. Outreach loop: §6.2.
502
- - **Resource pages / awesome lists.** The dev-ecosystem version of resource-page link building.
503
- Find them via `serp` on `<topic> resources`-shaped queries; submissions are manual.
444
+ keyword; getting added to one beats months of trying to outrank it. Loop: §6.2.
445
+ - **Resource pages / awesome lists.** The dev-ecosystem version of resource-page link building;
446
+ find them via `serp` on `<topic> resources`-shaped queries; submissions are manual.
504
447
  - **HARO-type platforms** (Featured, Qwoted, etc.). Agent drafts the pitch, human sends. Cap the
505
448
  experiment: a few per week for a month; no hits → stop.
506
449
 
507
- Explicitly out: mass templated outreach (spam — and structurally impossible here anyway, every
508
- email passes an approval gate), buying links, link exchanges. One more filter: **a link any
450
+ Explicitly out: mass templated outreach (spam — and structurally impossible here, every email
451
+ passes an approval gate), buying links, link exchanges. One more filter: **a link any
509
452
  competitor can replicate in an afternoon is worth little; price a strategy by how hard it is
510
- to copy.** Known data gap, stated honestly: there is no competitor-backlink command yet ("who
511
- links to this site" — Skyscraper/broken-link prospecting needs it); its trigger condition is
512
- documented in the product doc. Until then the target lists come from `serp` and manual research.
453
+ to copy.** Known data gap: no competitor-backlink command yet ("who links to this site" —
454
+ Skyscraper/broken-link prospecting needs it; trigger condition in the product doc); until then
455
+ target lists come from `serp` and manual research.
513
456
 
514
457
  ### 6.2 The outreach email loop
515
458
 
516
- The pitch email is where placement actually gets executed, and clize is the rare setup where
517
- the agent can run the whole loop — because the inbox is real and outbound is gated:
459
+ The pitch email is where placement actually gets executed; the inbox is real and outbound is
460
+ gated:
518
461
 
519
462
  ```
520
463
  serp → parasiteTargets → agent reads the target page, finds the contact
@@ -522,29 +465,27 @@ serp → parasiteTargets → agent reads the target page, finds the contact
522
465
  → replies land in the real inbox → agent reads them and follows up
523
466
  ```
524
467
 
525
- Discipline that keeps this white-hat: every email individually approved (the gate is the
526
- anti-spam structure, not a formality); a handful per week, not dozens; each pitch written from
527
- the target's actual page (name the section your entry fits, say why their readers care) if
528
- two pitches could be swapped between targets, they are templates and will read as such; log
529
- every attempt in the ledger's `placement` column (§3) target, date, status so the next
530
- session doesn't re-pitch the same page, and so a flat round can tell "we never placed anything"
531
- apart from "we placed and it didn't take".
468
+ Discipline that keeps this white-hat: every email individually approved; a handful per week, not
469
+ dozens; each pitch written from the target's actual page (name the section your entry fits, say why
470
+ their readers care two pitches that could be swapped between targets are templates and will read
471
+ as such); every attempt logged in the ledger's `placement` column (§3) target, date, status — so
472
+ the next session doesn't re-pitch the same page, and a flat round can tell "we never placed
473
+ anything" from "we placed and it didn't take".
532
474
 
533
- **Which channel actually sends the mail — decide before drafting, not after.** The loop above
534
- assumes the sending half is in place, and on most cold-start sites it is not:
475
+ **Which channel actually sends the mail — decide before drafting, not after.** The loop assumes
476
+ the sending half is in place, and on most cold-start sites it is not:
535
477
 
536
478
  - Run it through `clize email` when the sending domain (a subdomain is fine) is already set up
537
- there **and** outreach is a standing rhythm — several pitches a week, replies that need inbox
538
- follow-up across sessions. That is what the loop is built for.
479
+ there **and** outreach is a standing rhythm — several pitches a week, replies followed up from
480
+ the inbox across sessions.
539
481
  - At one-off volume — two or three pitches, main domain not on clize — the human sending your
540
- approved drafts from their everyday mailbox **is the optimal path, not a fallback**. Every
541
- send needs their approval anyway; an established personal mailbox out-delivers a freshly
542
- configured domain by a wide margin; and standing up DNS on a production domain for three
543
- emails is infrastructure nobody asked for. Deliver drafts + verified recipient addresses and
544
- you have done the agent's whole share.
545
- - Do not try to drive the user's webmail through a browser instead: host platforms gate
546
- agent-composed mail behind their own permission layer, separate from any approval the user
547
- gave you in chat. It will be blocked; don't burn the attempt.
482
+ approved drafts from their everyday mailbox **is the optimal path, not a fallback**: every
483
+ send needs their approval anyway, an established mailbox out-delivers a fresh domain by a
484
+ wide margin, and DNS on a production domain for three emails is infrastructure nobody asked
485
+ for. Drafts plus verified recipient addresses is the agent's whole share.
486
+ - Do not drive the user's webmail through a browser instead: host platforms gate agent-composed
487
+ mail behind their own permission layer, separate from any approval given in chat. It will be
488
+ blocked; don't burn the attempt.
548
489
  - Never route cold outreach through a transactional channel (Resend and the like) — complaint
549
490
  rates poison the sending reputation that receipts and alerts depend on.
550
491
 
@@ -553,58 +494,53 @@ assumes the sending half is in place, and on most cold-start sites it is not:
553
494
  ## 7. From row to page
554
495
 
555
496
  An SEO page differs from an ordinary page in three load-bearing ways. Its **brief is a
556
- worksheet row**, not a prose description — keyword, locale, serp verdict, intent, format; no
557
- row, no page. Its **success is measurable and lags by weeks** — so shipping the page and adding
558
- its keyword to `seo check --keywords` are one act, or the page is an orphan with no scoreboard.
559
- And its **format precedes creativity** — the SERP dictates the structure. That last one is an
560
- advantage: the shackles are exactly what suppress an agent's worst habit (competent, generic,
561
- unranked content). The more mechanical the constraint, the lower the output variance.
497
+ worksheet row** — keyword, locale, serp verdict, intent, format; no row, no page. Its **success
498
+ is measurable and lags by weeks** — so shipping the page and enrolling its keyword (§7.1 ⑤) are
499
+ one act, or the page is an orphan with no scoreboard. And its **format precedes creativity** —
500
+ the SERP dictates the structure, which is what suppresses an agent's worst habit: competent,
501
+ generic, unranked content.
562
502
 
563
503
  **Where the specs live:** `clize build site start` returns the page-type skeletons (landing /
564
504
  comparison / tool page) plus the on-page and GEO spec sheet — slug, title, meta, headings, FAQ
565
505
  schema rules. **That pack is the single source of truth for specs; this file only carries the
566
506
  judgment calls.** Don't improvise slugs and titles from memory.
567
507
 
568
- **If a page costs a session, the first deliverable is the generator, not the page.** A
569
- hand-written page is one session each; a page family — one stem × N locales, one `tool.js`, one
570
- skeleton, a strings file per locale (the spec pack's Page families section) — is a strings file
571
- each after the first. clize.ai went from one page per session to seven in one session the day
572
- a family generator existed, and tabledi shipped forty in two days from one. Build the generator
573
- before the second page of any family, and never machine-translate a family page.
574
-
575
- **On a site that already has tools, this round's page count is the locale siblings of the tools
576
- it has**, and the gate is each cell's own SERP (§7.2); a site without tools derives the set
577
- first (§7.2). Siblings come in two prices. A *format*
578
- tool (viewer, merge, split, convert) is one strings entry (tabledi: a `DICT` table in
579
- `tools/apps.js`; clize.ai: a `strings.<loc>.mjs`) — ten in a session is ordinary. A *text* tool
580
- (duplicates, compare, clean) carries locale semantics — full-width and half-width forms in
508
+ **If a page costs a session, the first deliverable is the generator, not the page.** A page
509
+ family — one stem × N locales, one `tool.js`, one skeleton, a strings file per locale (the spec
510
+ pack's Page families section) — costs a strings file per page after the first, where a
511
+ hand-written page costs a session (clize.ai: one page a session to seven the day a generator
512
+ existed; tabledi: forty in two days from one). Build the generator before the second page of
513
+ any family, and never machine-translate a family page.
514
+
515
+ **On a site that already has tools, this round's page count is `check.cells.missing` plus
516
+ `queue`** the locale siblings of the tools it has, counted by the product; a site without
517
+ tools derives the set first (§7.2). Siblings come in two prices: a *format* tool (viewer,
518
+ merge, split, convert) is one strings entry (tabledi: a `DICT` table in
519
+ `tools/apps.js`; clize.ai: a `strings.<loc>.mjs`) — ten in a session is ordinary; a *text*
520
+ tool (duplicates, compare, clean) carries locale semantics — full-width and half-width forms in
581
521
  Japanese, composed and decomposed accents in French — and a sibling that ignores them reports
582
- "0 duplicates" on a real file, which is gate 3 failed; budget two or three of those per session.
583
- Count existing tools × verified locale cells before anything else, and buy the SERPs the cells
584
- lack ($0.02 each) in the same breath tabledi had 23 tools and 6 markets; when a session
585
- finally counted, 15 cells had a SERP, 6 were passed and unbuilt, and "next batch" had been
586
- written beside them three times. New tools are code and tests, one to three per session: the
587
- next batch's rows, not this batch's excuse.
588
-
589
- **Building and publishing a page that passed the gates on the user's own site is never a
590
- question for the human.** The human's gates are money, changes that alter what the world already
591
- sees (a redirect, DNS, a canonical), sends, and posts on other people's platforms. Ask for those
592
- in one line and build while you wait never bundle the pages into the question. When a
593
- human-gated change shares a deploy with pages (a redirect map in the same `vercel.json`), split
594
- the deploy: ship the pages, hold the change. Step ⓪ is done when the pages are *live*, not
595
- committed — tabledi, 2026-09-02: one session built three things and ended asking about a
596
- redirect; the next found all three returning 404 in production and ended the same way. Four
597
- pages built across two sessions, zero live. A session does not end with built, undeployed pages.
522
+ "0 duplicates" on a real file (gate 3 failed); two or three of those per session. Read
523
+ `check.cells` before anything else (tabledi's grid, counted by hand on 2026-09-03: 15 tools × 7
524
+ markets, 51 cells open after three sessions of "next batch"). New tools are code and tests, one
525
+ to three per session the next batch's rows, not this batch's excuse.
526
+
527
+ **Building and publishing a page that passed the gates on the user's own site is never a question
528
+ for the human.** The human's gates are money, changes that alter what the world already sees (a
529
+ redirect, DNS, a canonical), sends, and posts on other people's platforms. Ask for those in one line
530
+ and build while you wait never bundle the pages into the question; when a human-gated change
531
+ shares a deploy with pages (a redirect map in the same `vercel.json`), ship the pages and hold the
532
+ change. Step is done when the pages are *live*, not committed (tabledi, 2026-09-02: four pages
533
+ built across two sessions, zero live). A session does not end with built, undeployed pages.
598
534
 
599
535
  ### 7.1 The pipeline — five steps, each with a pass/fail
600
536
 
601
537
  | step | act | it passed if |
602
538
  | --- | --- | --- |
603
- | ① brief | five fields, written into the row before a word of the page: **intent** — what the searcher wants, from the query, the shapes in the top 10, and Search Console when the site already earns on it (§4); **occupants** — open and *read* the top 3–5 pages, not their titles: structure, length, what each answers, promises and lacks (you fetch them yourself; there is no command for this and $0); **product truth** — what the product actually does for this intent (gate 3) and what only it has: first-party data, a working tool, a capability the occupants lack; **angle** — one sentence naming an occupant gap that a product truth fills; **form** — page type from what the top 10 is, length ≈ closest-shaped rival × 1.1–1.2, every H2 mapped to an occupant or a gap, the first 200 words, the FAQ in that market's phrasing. One brief per family; locale siblings change terminology and FAQ only | the angle names a gap *and* an asset — no angle, no page, and the row becomes `skip: no angle`. The three pages that worked had one (clize's OpenClaw page: "an inbox the agent owns" against two "borrow your Gmail" occupants; tabledi's Japanese dedupe: full-width forms, which a wall of tutorials never mentions; kunavo's 529 page: real failover numbers nobody on the page had); the five that read zero did not |
539
+ | ① brief | five fields, written into the row before a word of the page: **intent** — what the searcher wants, from the query, the top-10 shapes, and Search Console when the site already earns on it (§4); **occupants** — open and *read* the top 3–5 pages, not their titles: structure, length, what each answers, promises and lacks (fetch them yourself; no command, $0); **product truth** — what the product actually does for this intent (gate 3) and what only it has: first-party data, a working tool, a capability the occupants lack; **angle** — one sentence naming an occupant gap that a product truth fills; **form** — page type from the top 10, length ≈ closest-shaped rival × 1.1–1.2, every H2 mapped to an occupant or a gap, the first 200 words, the FAQ in that market's phrasing. One brief per family; locale siblings change terminology and FAQ only | the angle names a gap *and* an asset — no angle, no page, and the row becomes `skip: no angle`. The three pages that worked had one (clize's OpenClaw "inbox the agent owns"; tabledi's Japanese full-width dedupe; kunavo's 529 failover numbers); the five that read zero did not |
604
540
  | ② produce | skeleton from `build site start`, judgment from here, words and code from you | first 200 words answer the query completely; your definition sentence is verbatim-identical site-wide |
605
541
  | ③ self-check | against the spec sheet — there is deliberately no audit command | visible FAQ ↔ JSON-LD strictly 1:1; ≥2 internal links with varied anchors |
606
542
  | ④ deploy | ship it | page live, in sitemap |
607
- | ⑤ enroll | `seo check --keywords <+this page's keyword>` (`<keyword>@<locale>` for a non-English cell otherwise it is priced as en-US and reads `no_data`), and write `shipped:<url>, <date>` in the ledger | the keyword shows in check output under `pending` until a window that includes the ship date closes, then under `latest` or `unseen` |
543
+ | ⑤ enroll | `seo check --add-keywords "<keyword>@<locale>#<family>"` the next check binds the live page to the cell (`built`); nothing to write in the ledger | the cell leaves `queue`; the keyword shows under `pending` until a window that includes the ship date closes, then under `latest` or `unseen` |
608
544
 
609
545
  Page type from row type: variant row → landing; `alternative`/`vs` row → comparison; action-
610
546
  intent row → use-case; tool-intent row → tool page.
@@ -614,101 +550,92 @@ intent row → use-case; tool-intent row → tool page.
614
550
  The one page type where the content *is* the function — and the strongest link asset (§6.1).
615
551
 
616
552
  **A site with fewer than five tools has no multiplier, and inventing the tool set is its first
617
- production task** — not a product decision to wait for. Three sources, all paid for already or
553
+ production task** — not a product decision to wait for. Three sources, all already paid for or
618
554
  free: (1) the sweep (§1.1) — every rival keyword shaped like a calculator, converter, counter,
619
- checker, estimator or generator; tabledi's teardown found rows.com, formulabot and quadratic
620
- earn their organic traffic from free calculators, not product pages, and that finding sat in a
621
- ledger for three days without becoming a rule; (2) the product's own data a catalog with
622
- prices is a cost calculator, a limits table is a context-window checker, a media catalog is a
623
- generation-cost estimator, a list of formats is a converter; every number the product already
624
- maintains is a tool nobody else can keep current; (3) the neighbours of the tools you have.
555
+ checker, estimator or generator (tabledi's teardown: rows.com, formulabot and quadratic earn
556
+ their organic traffic from free calculators, not product pages); (2) the product's own data a
557
+ price catalog is a cost calculator, a limits table a context-window checker, a media catalog a
558
+ generation-cost estimator, a format list a converter; (3) the neighbours of the tools you have.
625
559
  Each candidate gets an English SERP ($0.02) before a line of code; two or three tools per
626
560
  session is the honest rate; once the family exists, §7's sibling rule multiplies it by every
627
- verified market. kunavo, 2026-09-03: two tool URLs, 43 hand-written locale guides, six pages a
628
- round — the page-type mix set that ceiling, not the process.
561
+ verified market (kunavo, 2026-09-03: two tool URLs, 43 hand-written locale guides, six pages a
562
+ round — the page-type mix set that ceiling).
629
563
 
630
564
  Judgment calls that matter:
631
565
 
632
566
  - **Three words are the whole quality bar: free, instant, no signup.** Tool above the fold,
633
- explanatory content and FAQ below it. The skeleton in the spec pack encodes this layout.
567
+ explanatory content and FAQ below it; the skeleton in the spec pack encodes this layout.
634
568
  - **The boundary is the browser sandbox.** Hosted sites are static: build only tools that run
635
- entirely client-side (generators, converters, calculators — llms.txt generator, robots.txt
636
- generator, JSON-LD generator). Tools that must fetch other people's sites (checkers) die on
637
- CORS — don't attempt them until the platform offers a fetch proxy.
638
- - **One tool × N locales is legitimate multiplication, and the gate is per cell.** Tool UI
639
- translates almost for free, and the non-English cells of your matrix are the low-competition
640
- ones. Each locale page is a real, distinct intent this is not page-stuffing. Build every
641
- locale cell whose *own* SERP is not a wall (`seo serp --locale`, $0.02); the English page's
642
- impressions are not the gate, because the same intent draws a different page in each market
643
- kunavo's `claude code pricing`: `official_wall` in de-DE and es-ES, `open` in ja-JP and
644
- fr-FR; one keyword, four verdicts. What does not multiply: marketing and landing pages. Read
645
- that evidence for what it varied, not for what it sounds like: clize.ai's 72 translated
646
- landing pages earn about what their English originals earn — impressions in the tens, zero
647
- clicks — so the failure is the *type*, in every language; kunavo's 199 untranslated copies
648
- were duplicates, collapsed by canonicalization, and say nothing about locales; the locale
649
- pages that do earn on both sites are translated guides and tools (kunavo's Korean pricing
650
- guide is its top non-brand page). The bar for adding a locale to a marketing page is local
651
- non-brand impressions on the ones that exist — indexing is the floor, not the pass. Locale is
652
- not a page-generation primitive; a SERP-backed intent is.
569
+ entirely client-side (generators, converters, calculators — llms.txt, robots.txt, JSON-LD
570
+ generators). Tools that must fetch other people's sites (checkers) die on CORS — don't attempt
571
+ them until the platform offers a fetch proxy.
572
+ - **One tool × N locales is legitimate multiplication, and the product keeps the grid.** Each
573
+ locale page is a real, distinct intent — not page-stuffing. `check.cells` derives every page's
574
+ family from its hreflang cluster and lists `missing` (family × served market with no page and
575
+ no keyword) and `queue` (a keyword with no page); a `verified` family (any page earning, or
576
+ any keyword with an enterable verdict) needs **no SERP for its siblings** one SERP per new
577
+ family, one page per family per market (a second phrasing is a second keyword on that page).
578
+ Marketing and landing pages do not multiply clize.ai's 72 translated landing pages earn
579
+ what their English originals earn, which is nothing; the locale pages that earn are tools and
580
+ guides.
653
581
  - **Pick tools with a shelf life.** Protocol- and format-level tools (llms.txt, schema, robots)
654
- keep earning links for years; trend-chasing tools die with the trend. Ask: will anyone search
655
- this in a year?
582
+ keep earning links for years; trend-chasing tools die with the trend. Will anyone search this
583
+ in a year?
656
584
 
657
585
  ### 7.3 The four gates
658
586
 
659
587
  Written for an agent with zero SEO experience to follow without wrecking anything — the gates
660
588
  do the protecting, not experience:
661
589
 
662
- 1. **One page, one row.** Every page traces to a worksheet row that has a serp verdict. No
663
- $0.02 serp run, no pagethe price of skipping it is writing pages into an
664
- `official_wall`.
590
+ 1. **One page, one cell.** Every page is a (family, market) cell the product can see in
591
+ `check.cells`, and its family is verified earning already, or holding an enterable
592
+ verdict from one SERP. A family's first page never skips that SERP; its siblings never
593
+ need one.
665
594
  2. **The SERP writes the outline.** Step ① is derivation from `items`, not free composition.
666
595
  3. **Promise only what exists.** Features described must actually work; for a tool page, run
667
596
  the tool yourself before shipping. Pages that oversell poison the domain's trust and your
668
597
  own E-E-A-T.
669
598
  4. **Throttle by the site, not the session.** Google's scaled-content rule has three terms —
670
599
  many pages, built to manipulate ranking, not helping users — counted per site, with no term
671
- for how many pages one session shipped and none for how they were produced. So there is no
672
- page count here, per batch or per session: several sessions build on one site at once, and a
673
- per-session cap neither sees the site nor protects it. A batch is gated by the site's
674
- composition, three checks:
675
- - **each page has its own row and its own SERP** (gate 1) — the query exists and is
676
- enterable;
600
+ for how many pages one session shipped or how they were produced. So there is no page count
601
+ here, per batch or per session. A batch is gated by the site's composition,
602
+ three checks:
603
+ - **each page is a verified cell** (gate 1);
677
604
  - **the family is not a template with the noun swapped** — before deploy, diff the
678
- non-skeleton text of each new page against its siblings and the site. Pages that are mostly
679
- identical are doorway pages whatever their keywords say, and one thin family drags the
680
- whole site's classifier score, tool pages included. Distinct real content per page: a
681
- locale page written in-locale, a host page whose install and config really differ;
605
+ non-skeleton text of each new page against its siblings and the site. Mostly-identical
606
+ pages are doorway pages whatever their keywords say, and one thin family drags the whole
607
+ site's classifier score, tool pages included. Distinct real content per page: a locale page
608
+ written in-locale, a host page whose install and config really differ;
682
609
  - **the last batch is being indexed** — `gsc.pages.unseen` (§9) shows the previous batch's
683
- `index`; find the batch by `firstSeen`, and book the counts in the ledger's batch table (§3).
684
- Read the four states apart: `URL is unknown to Google` and `Discovered - currently not
685
- indexed` are the queue (a day-old batch sits there; not a verdict); `Crawled - currently
686
- not indexed` is Google's verdict on a page it has read — after you rule out your own hand
687
- (a canonical pointing elsewhere, hreflang missing or one-way, a stray `noindex`), which
688
- produces the same state. Mostly indexed → ship the next family. Mostly crawled-not-indexed
689
- on a clean implementation → the round is indexing and pruning, not shipping. This check
690
- paces shipping; it does not certify composition kunavo's 440 locale model pages indexed
691
- fine and earned nothing. Composition is the second check and the retire rule.
610
+ `index`; find the batch by `firstSeen` and book the counts in the batch table (§3). `URL
611
+ is unknown to Google` and `Discovered - currently not indexed` are the queue (a day-old
612
+ batch sits there; not a verdict); `Crawled - currently not indexed` is Google's verdict on
613
+ a page it has read — once you rule out your own hand (a canonical pointing elsewhere,
614
+ hreflang missing or one-way, a stray `noindex`; `cells.defects` lists the hreflang ones),
615
+ which produces the same state. Mostly indexed → ship the next family; mostly
616
+ crawled-not-indexed on a clean implementation → the round is indexing and pruning, not
617
+ shipping. This check paces shipping; it does not certify composition (kunavo's 440 locale
618
+ model pages indexed fine and earned nothing) that is the second check and the retire
619
+ rule.
692
620
  Impressions are not the gate for the next batch: at zero authority they arrive five to six
693
- weeks after shipping and clicks may not arrive in a quarter, so a rule that waits for them
694
- ships nothing for months that was the mechanism behind five pages a month. Waiting is for
695
- *deciding a new page type* (§10), never for the siblings of a type already decided. The
696
- retire rule is the other half of shipping fast: a page indexed for two windows with no
697
- impressions, or refused by the index for two, is retired: `noindex` by default (the page keeps
698
- serving users, only its index exposure goes), merge or redirect when another page carries the
699
- intent, delete only what nobody visits. The composition stays clean only if dead pages leave
700
- the index.
621
+ weeks after shipping and clicks may not arrive in a quarter; a rule that waits for them ships
622
+ nothing for months. Waiting is for *deciding a new
623
+ page type* (§10), never for siblings of a type already decided. The retire rule is the other
624
+ half: a page indexed for two windows with no impressions (`cells.retire` lists them), or
625
+ refused by the index for two, is retired `noindex` by default (it keeps serving users; only
626
+ its index exposure goes), merge or redirect when another page carries the intent, delete
627
+ only what nobody visits. The composition stays clean only if dead pages leave the index.
701
628
 
702
629
  ### 7.4 E-E-A-T floor and locales
703
630
 
704
631
  AI-generated content gets judged hardest on what it usually lacks: a real author entity (name,
705
632
  bio, `sameAs` to real profiles) on cornerstone pages, cited sources for claims and numbers, and
706
- a visible dated update. These are cheap to add and expensive to lack.
633
+ a visible dated update. Cheap to add, expensive to lack.
707
634
 
708
- Multi-locale placement (you enumerated non-English cells in §1.2 — this is the other half):
709
- unified-operation sites use slash paths (`/de/`, `/ja/`) not subdomains; hreflang pairs point
710
- both ways; keep the same slug stem across locales. Write in-locale terminology, never machine-
711
- translate the English page.
635
+ Multi-locale placement (the other half of the non-English cells in §1.2): unified-operation
636
+ sites use slash paths (`/de/`, `/ja/`) not subdomains; hreflang pairs point both ways; keep the
637
+ same slug stem across locales. Write in-locale terminology, never machine-translate the English
638
+ page.
712
639
 
713
640
  ---
714
641
 
@@ -716,32 +643,30 @@ translate the English page.
716
643
 
717
644
  Retrieval-augmented engines quote passages, not pages. What survives extraction:
718
645
 
719
- - **Answer completely in the first 200 words.** Assume the extractor never reaches your second
646
+ - **Answer completely in the first 200 words.** Assume the extractor never reaches the second
720
647
  section.
721
- - **One-sentence extractables.** Each key claim should stand alone when lifted out of context.
722
- Pronouns and "as mentioned above" destroy quotability.
648
+ - **One-sentence extractables.** Each key claim stands alone when lifted out of context;
649
+ pronouns and "as mentioned above" destroy quotability.
723
650
  - **Statistics and named sources.** Concrete numbers with attribution get quoted; adjectives
724
651
  don't.
725
- - **Define your terms verbatim and identically everywhere.** If your definition sentence varies
726
- between pages, no single phrasing accumulates authority.
652
+ - **Define your terms verbatim and identically everywhere.** A definition that varies between
653
+ pages lets no single phrasing accumulate authority.
727
654
  - **Machine-readable surface**: `llms.txt`, schema.org markup, a sitemap, and IndexNow pings.
728
655
 
729
656
  ### Measuring whether it worked
730
657
 
731
- The scoreboard is `check` → `traffic.ai`. A referral from an AI engine is a real user who
732
- clicked through — that is the end state, and the first non-zero is the milestone (§9). While it
733
- is still all zeros, the interim instrument is a **manual spot-check**: every week or two, ask
734
- the 3–5 questions your money pages answer in the engines themselves (~15 minutes, logged in)
735
- and note who gets named. Zero is a reading.
736
-
737
- **Do not build a citation-probe cron** a saved prompt set fired at N engines on a schedule.
738
- Field-tested and rejected: self-authored prompts carry self-confirmation bias, a low-authority
739
- site's probe is a flat zero line that still costs keys and upkeep, and a measurement nobody is
740
- present to act on is inventory (one such cron sat dark for two weeks without a decision
741
- changing). A probe earns its keep only when there is something to *attribute* — sustained AI
742
- referrals, a real attribution question, a before/after around a launch. Until then, referrers
743
- plus the spot-check; and all AI-citation measurement is sampling — trends against your own
744
- baseline, never absolute share.
658
+ The scoreboard is `check` → `traffic.ai`: an AI-engine referral is a real user who clicked
659
+ through, and the first non-zero is the milestone (§9). While it is all zeros, the interim
660
+ instrument is a **manual spot-check**: every week or two, ask the 3–5 questions your money
661
+ pages answer in the engines themselves (~15 minutes, logged in) and note who gets named. Zero
662
+ is a reading.
663
+
664
+ **Do not build a citation-probe cron** (a saved prompt set fired at N engines on a schedule).
665
+ Field-tested and rejected: self-authored prompts self-confirm, a low-authority site's probe is a
666
+ flat zero that still costs keys and upkeep, and a measurement nobody is present to act on is
667
+ inventory. A probe earns its keep only when there is something to *attribute* sustained AI
668
+ referrals, a before/after around a launch. Until then, referrers plus the spot-check; all
669
+ AI-citation measurement is sampling trends against your own baseline, never absolute share.
745
670
 
746
671
  ---
747
672
 
@@ -752,26 +677,25 @@ baseline, never absolute share.
752
677
  `rank.source` is always `"gsc"`: positions come from Search Console, and measurement makes no
753
678
  upstream calls — the only thing `check` may pay for is pricing words it has never priced.
754
679
 
755
- - `position` is the **impression-weighted average over `rank.window`**, not a rank at a moment;
680
+ - `position` is the **impression-weighted average over `rank.window`**, not a rank at a moment:
756
681
  one good day barely moves it, and it is not comparable to a scraped SERP position. `delta` is
757
- positive when you moved up, against `rank.prevWindow`; `series` is weekly, newest first, with
682
+ positive when you moved up, against `rank.prevWindow`; `series` is weekly, newest first,
758
683
  empty weeks absent — read the dates.
759
684
  - **`movers` runs on two axes**: position shifted by 3+, *or* impressions halved / doubled with
760
685
  the larger side at 20+ (`prevImpressions` / `prevClicks` sit on every row). Traffic is
761
- impressions × CTR, and position alone is blind to the event that matters most: tabledi's
762
- duplicate-finder page fell from 3,088 impressions to 50 while its `delta` read −0.5. A word
763
- that had impressions last window and none now appears with `position: null`. **A collapse
764
- with a flat position is a page problem — go to `gsc.pages` before you touch the ledger.**
686
+ impressions × CTR, and position alone is blind to the event that matters most (tabledi's
687
+ duplicate-finder page fell from 3,088 impressions to 50 while `delta` read −0.5). A word with
688
+ impressions last window and none now appears with `position: null`. **A collapse with a flat
689
+ position is a page problem — go to `gsc.pages` before you touch the ledger.**
765
690
  - `pending` lists words **enrolled after `rank.window.to`**: no reading yet, not in `unseen`, no
766
- signal form. A zero on a pending word says nothing. One exception you apply yourself: a word
691
+ signal form; a zero on a pending word says nothing. One exception you apply yourself: a word
767
692
  enrolled for a page older than the window reads as `unseen`.
768
693
  - Every row carries **`sv` and `kd` next to the Search Console numbers** — demand and delivery
769
694
  side by side. `sv: 27100` at `position: 74` and `sv: 0` at `position: 4.5` are different worlds.
770
- - `unseen` lists words **Search Console did not see this window**. Not "not ranking" GSC has a
695
+ - `unseen` lists words **Search Console did not see this window** not "not ranking"; GSC has a
771
696
  row only once you get impressions. A real position for one of them is a deliberate
772
697
  `clize seo serp <keyword>` (~$0.02); never for all of them. Non-English cells appear as
773
- `word@locale`, the form you enrolled them in; `latest` / `pending` / `signals` rows carry
774
- `locale` as a field.
698
+ `word@locale`, as enrolled; `latest` / `pending` / `signals` rows carry `locale` as a field.
775
699
  - `rank: null` means the round had nothing to synthesise from (no Search Console access, or no
776
700
  list) — read `notes`. **Competitor positions are not in `check`**; `--competitors` is remembered
777
701
  configuration, and a head-to-head is `seo serp <keyword>`.
@@ -780,51 +704,47 @@ upstream calls — the only thing `check` may pay for is pricing words it has ne
780
704
 
781
705
  Every `rank.latest` row carries **`topPage`** — the page of yours that took the most impressions
782
706
  on that query — and **`pages`**, how many of yours got any. Pure aggregate; the judgment is the
783
- comparison with the ledger's `target page` (§3):
707
+ comparison with the page the cell is bound to (`check.cells`, §3):
784
708
 
785
709
  | configuration | what it means | what to do |
786
710
  | --- | --- | --- |
787
- | **Accidental carrier** — ledger `page` is `none`, `topPage` has a value | Google picked a carrier out of pages you built for something else | Go with its pick: internal links and a section that answers the query on *that* page. Cheapest double-down there is |
788
- | **Mismatch** — `target page` is A, `topPage` is B | A is not recognised as the answer | Structure, not content: links and anchors into A, title/H1 alignment, is A indexed. More words on A is the reflex to resist |
789
- | **Self-cannibalisation** — `pages` > 1 | Your pages are splitting one query | Merge, or canonical one to the other — after looking: `pages` is a count, not a split, and `2` with one page taking almost everything is ordinary |
711
+ | **Accidental carrier** — the cell has no page of its own, `topPage` has a value | Google picked a carrier out of pages you built for something else | Go with its pick: internal links and a section that answers the query on *that* page. Cheapest double-down there is |
712
+ | **Mismatch** — the cell's page is A, `topPage` is B | A is not recognised as the answer | Structure, not content: links and anchors into A, title/H1 alignment, is A indexed. More words on A is the reflex to resist |
713
+ | **Self-cannibalisation** — `pages` > 1 (`cells.cannibal` expands it) | Your pages are splitting one query | Merge, or canonical one to the other — after looking: `pages` is a count, not a split, and `2` with one page taking almost everything is ordinary |
790
714
 
791
715
  ### `gsc.pages` — the page face
792
716
 
793
- The question the product exists for is "how much traffic does the final page get", answered by
794
- page since 0.34.0 three facts side by side, no judgment. Reading it is the first fifteen
795
- minutes of a round, not the round: the shapes below say what to fix, and the round still
796
- enumerates and builds (§10).
717
+ Three facts per page, no judgment (by page since 0.34.0). Reading it is the first fifteen minutes of
718
+ a round, not the round: the shapes below say what to fix, and the round still enumerates and builds
719
+ (§10).
797
720
 
798
721
  | list | what is in it | the facts per row |
799
722
  | --- | --- | --- |
800
723
  | `latest` | the 20 pages with the most impressions this window | `impressions` / `clicks` and their `prev*` twins, `position`, live `status` (final HTTP status; `finalUrl` when it landed elsewhere) |
801
724
  | `movers` | pages whose impressions halved or doubled (larger side 20+), including pages that went to zero | the same, plus `index` for the collapsed ones |
802
- | `unseen` | sitemap URLs with no impressions this window — most recently first-seen first, then `lastmod`; up to 200, `unseenTotal` says how many there are | `firstSeen` (the date `check` first saw the URL in the sitemap), `status`, `index` — Google's own words: `Submitted and indexed`, `Crawled - currently not indexed`, `Discovered - currently not indexed`, `URL is unknown to Google` |
725
+ | `unseen` | sitemap URLs with no impressions this window — newest `firstSeen` first, then `lastmod`; up to 200, `unseenTotal` gives the total | `firstSeen` (when `check` first saw the URL in the sitemap), `status`, `index` — Google's own words: `Submitted and indexed`, `Crawled - currently not indexed`, `Discovered - currently not indexed`, `URL is unknown to Google` |
803
726
 
804
727
  Read it as three shapes, in this order:
805
728
 
806
729
  - **Lost page** — in `movers`, impressions collapsed, `status` ≠ 200 or a `finalUrl` elsewhere.
807
730
  Shape B: restore the URL or 301 it to the page with the same intent (a mismatched redirect is
808
- a soft 404), request indexing, leave the ledger alone — nothing can be read off a window in
809
- which the page was dead.
810
- - **Not on the shelf** — in `unseen` with `index` anything but indexed. Not in the race yet;
811
- discovery and content cannot help it. Internal links, sitemap `lastmod`, an indexing request,
812
- then wait a window. Thirty-five `unseen` words on a site that just shipped sixty pages are
813
- this shape until proven otherwise. This list is also the batch gate (§7.3): the last batch
814
- mostly `indexed` → ship the next family; mostly `Crawled - currently not indexed` → Google's
815
- own verdict on those pages, and this round prunes instead of shipping.
731
+ a soft 404), request indexing, leave the ledger alone — a window in which the page was dead
732
+ reads nothing.
733
+ - **Not on the shelf** — in `unseen` with `index` anything but indexed: not in the race yet,
734
+ and discovery and content cannot help it. Internal links, sitemap `lastmod`, an indexing
735
+ request, then wait a window. This list is also the batch gate (§7.3 gate 4).
816
736
  - **Indexed and ignored** — in `unseen` with `index` indexed, for a window after its ship date.
817
- Only now is it a keyword question (§4, §5); after a second such window it is a retire
818
- question (§7.3).
737
+ Only now a keyword question (§4, §5); after a second such window a retire question (§7.3,
738
+ `cells.retire`).
819
739
 
820
740
  Index status costs a quota call per URL, so `check` inspects at most 30 per run — collapsed
821
- movers first, then the newest unseen sitemap URLs, then top pages — and `notes` says how many.
741
+ movers first, then the newest unseen sitemap URLs, then top pages — and `notes` says how many;
822
742
  `index: null` means *not inspected this round*, never "not indexed". `unseen` order follows
823
- `firstSeen`, then `lastmod` so a site-wide edit that stamps every page with today's `lastmod`
824
- (clize.ai, 2026-09-02: 124 of 124) cannot push the newest batch out of the inspection budget; on
825
- the first check after 0.35.0 `firstSeen` is seeded from `lastmod`, and from the next check on a
826
- new URL is simply new. If `notes` says inspection is unavailable, the service account is
827
- `Restricted`; `Full` unlocks it. No sitemap means no `unseen` list — publish one.
743
+ `firstSeen`, then `lastmod`, so a site-wide edit that stamps every page with today's `lastmod`
744
+ (clize.ai, 2026-09-02: 124 of 124) cannot push the newest batch out of the inspection budget
745
+ (the first check after 0.35.0 seeds `firstSeen` from `lastmod`). If `notes` says inspection is
746
+ unavailable, the service account is `Restricted`; `Full` unlocks it. No sitemap means no
747
+ `unseen` list — publish one.
828
748
 
829
749
  ### `rank.signals` — the cross-source read, done for you
830
750
 
@@ -834,27 +754,27 @@ so you can overrule it:
834
754
 
835
755
  | form | the configuration | how to read it |
836
756
  | --- | --- | --- |
837
- | `pre_emergence` | priced volume is **0**, or the window's impressions are **at least twice** the priced monthly volume — and Search Console shows real impressions (10+) | Demand is ahead of the keyword tools; on a low-authority site this is the cheapest entry there is. Write the page. A small `sv` next to a large impression count is the same fact — never let the `sv` downgrade the row |
838
- | `authority_limited` | many impressions, position 50+, **zero clicks** | Google offers the keyword surface and withholds the position. An authority bottleneck **on that theme** — another page on it will not move it; go do §6.1. The label is per keyword: production on other themes continues |
757
+ | `pre_emergence` | priced volume is **0**, or the window's impressions are **at least twice** the priced monthly volume — and Search Console shows real impressions (10+) | Demand is ahead of the keyword tools; on a low-authority site the cheapest entry there is. Write the page. A small `sv` next to a large impression count is the same fact — never let `sv` downgrade the row |
758
+ | `authority_limited` | many impressions, position 50+, **zero clicks** | Google offers the surface and withholds the position: an authority bottleneck **on that theme** — another page on it will not move it; go do §6.1. Per keyword: production on other themes continues |
839
759
  | `demand_no_surface` | real search volume, **no impressions at all** this window | Google is not putting you on the shelf. A discovery question (what occupies it? → `seo serp`), not a measurement one |
840
760
 
841
761
  `demand_no_surface` is capped at the five most attackable words (lowest KD, then volume;
842
762
  `pending` words never take this form); the full list is `rank.unseen`. On a cold-start site
843
- nearly every word is in this shape — normal state, not a finding. An empty `signals` is not a
844
- failure. There is deliberately no `data_conflict` form: `check` has one position source; when
845
- a scrape disagrees with Search Console, believe Search Console — a 28-day average of what
846
- Google served against one personalised fetch of a rotating page.
763
+ nearly every word is in this shape — normal state, not a finding and an empty `signals` is
764
+ not a failure. There is deliberately no `data_conflict` form: `check` has one position source,
765
+ and when a scrape disagrees with Search Console, believe Search Console — a 28-day average of
766
+ what Google served against one personalised fetch of a rotating page.
847
767
 
848
768
  ### `keywords.byBand`, `traffic`, `gsc`
849
769
 
850
770
  - `byBand` counts **only priced keywords**; the unpriced gap is stated in `notes`. `no_data`
851
- inside it means "we asked and the upstream has no row" — a finding about a long-tail word,
852
- not about demand (§5).
771
+ inside it means "we asked and the upstream has no row" — about a long-tail word, not about
772
+ demand (§5).
853
773
  - `traffic.ai` is always present, **including when it is all zeros — zero is the finding**, and
854
- the first non-zero referral is the milestone. The numbers are adaptively sampled and rounded;
774
+ the first non-zero referral is the milestone. The numbers are adaptively sampled and rounded:
855
775
  compare over time, never quote as exact counts. Same-host referrers are already excluded.
856
- - `gsc.newQueries` is the feedback loop closing (§1.3) — the most valuable output of the whole
857
- command; fold them into the matrix. `gsc: null` is not an error: read `notes`, usually the
776
+ - `gsc.newQueries` is the feedback loop closing (§1.3) — the most valuable output of the
777
+ command; fold them into the matrix. `gsc: null` is not an error: read `notes`; usually the
858
778
  service account is not on the property yet.
859
779
 
860
780
  ### The one rule that ties it together
@@ -869,75 +789,72 @@ sentence (`authority_limited`); the roundups still come from a deliberate `seo s
869
789
  ## 10. The cycle
870
790
 
871
791
  **The loop starts at measurement, and its purpose is allocation.** Between rounds the only
872
- thing that changes is what *your* actions did to the world, and that shows up only in `check`,
873
- which is free (sv/kd are monthly data, SERPs move slowly). The entry read is the branch point:
874
- each round's real question is **where the next unit of work goes** — double down where a signal
875
- appeared, stop where none did, and keep enumerating cells the ledger has not priced yet.
876
-
877
- **A round is a pipeline, and it opens by building.** ⓪ **ship the qualified batch** — every
878
- `to build` row from the last round and every plan cell with its own SERP verdict (§3), in every
879
- ledger file, each built from its brief (§7.1 ①) — before reading a single number, while the
880
- session's budget is whole → ① read the
881
- feedback (`check`, free) → ② allocate (double down / stop loss / new bet) → ③ execute what is
882
- cheap now (siblings, retargets, placement drafts) and write the rest as the next session's
883
- `to build` rows → ④ book it (§3) → ⑤ report it (two tables, below). This round's analysis
884
- qualifies the *next* round's batch; it does not postpone this one's. Step ⓪ is the step that
885
- vanished in three consecutive runs: each read, diagnosed, wrote a ledger, named itself an
886
- "analysis round" and handed the pages to "next time". Step ④ is the other one that gets
887
- skipped, and skipping it breaks step ② two weeks later: "flat, no signal" and "flat, no signal,
888
- *and we already pitched five roundups*" are different rows, and only the ledger can tell them
889
- apart.
792
+ thing that changes is what *your* actions did, and that shows up only in `check`, which is free.
793
+ Each round's real question is
794
+ **where the next unit of work goes** — double down where a signal appeared, stop where none
795
+ did, and keep enumerating cells the ledger has not priced yet.
796
+
797
+ **A round is a pipeline, and it opens by building.** ⓪ **ship the queue** — every cell in
798
+ `check.cells.queue` (a keyword with no page) and every `missing` cell you can phrase, siblings
799
+ from the family brief and new families from their own (§7.1 ①) — before reading a single
800
+ number → ① read the feedback (`check`, free) → ② allocate
801
+ (double down / stop loss / new bet) → ③ execute what is cheap now (siblings, retargets,
802
+ placement drafts) and write the rest as the next session's `to build` rows → ④ book it (§3) →
803
+ ⑤ report it (two tables, below). This round's analysis qualifies the *next* round's batch; it
804
+ does not postpone this one's. Step ⓪ vanished in three consecutive runs, each naming itself an
805
+ "analysis round"; step is the other one skipped, and without it step cannot tell "flat, no
806
+ signal" from "flat, *and we already pitched five roundups*".
890
807
 
891
808
  ```
892
809
  clize seo check # free — every session on an existing site starts here
893
810
  ```
894
811
 
895
812
  **Domain of the loop: a site that exists.** `check` needs `--domain` (or a clize project
896
- directory). No site yet? That is pre-cycle work: discovery (§1), first batch (§7), enroll — the
897
- cycle starts at that first check. **Round one is not special — it is the round that reads
898
- zero.** The zeros are the baseline; the entry read still pays before you spend a cent: it
899
- surfaces the GSC service-account setup (a 2-minute human step — hand it over now, in parallel),
900
- and on a site with history it hands you free seeds (`gsc.topQueries` / `newQueries`).
813
+ directory). No site yet? Pre-cycle work: discovery (§1), first batch (§7), enroll — the cycle
814
+ starts at that first check. **Round one is not special — it is the round that reads zero.** The
815
+ zeros are the baseline, and the entry read still pays before you spend a cent: it surfaces the
816
+ GSC service-account setup (a 2-minute human step — hand it over now, in parallel) and, on a
817
+ site with history, free seeds (`gsc.topQueries` / `newQueries`).
901
818
 
902
819
  ### ②–③ Allocate, then execute — branch on what the read says
903
820
 
904
821
  | the read says | this round is |
905
822
  | --- | --- |
906
- | nothing yet (round one), or `demand_no_surface` across the board | **discovery + first bets**: `seo competitors <2–3 rivals>` → capability matrix (§1.2, seeded with anything the entry read gave you) → `seo keywords <the whole list>` in one call → drop `wall` → `seo serp` each survivor → ledger rows (§3) → first batch: **at least three page types, every buildable row in each**, through the §7 pipeline (a generator first for any family, specs from `build site start`, prose per §8) → enroll: `seo check --keywords <survivors> --brand <you>` → start placement (§6) immediately do not wait for rankings to "settle"; that wait is how sites end up at 120% on-page and zero authority. Total ≈ $1 |
907
- | `movers` rising, a `rank.latest` row's clicks first going non-zero, or `traffic.ai.total` first non-zero | **double down** — the branch the whole flywheel exists for: enumerate that keyword's sibling cells and price only the new ones (old ones are cached), add internal links into the page that is actually carrying it (`topPage` on that row is Google's answer, the ledger's `target page` is yours — when the two disagree, §9), add placement positions on that theme. Returns compound where the signal already is |
823
+ | nothing yet (round one), or `demand_no_surface` across the board | **discovery + first bets**: `seo competitors <2–3 rivals>` → capability matrix (§1.2, seeded from the entry read) → `seo keywords <the whole list>` in one call → drop `wall` → `seo serp` each survivor → ledger rows (§3) → first batch: **at least three page types, every buildable row in each**, through the §7 pipeline (a generator first for any family, specs from `build site start`, prose per §8) → enroll: `seo check --keywords <survivors> --brand <you>` → start placement (§6) immediately, without waiting for rankings to "settle". Total ≈ $1 |
824
+ | `movers` rising, a `rank.latest` row's clicks first going non-zero, or `traffic.ai.total` first non-zero | **double down** — the branch the flywheel exists for: enumerate that keyword's sibling cells and price only the new ones (old ones are cached), add internal links into the page actually carrying it (`topPage` is Google's answer, the cell's page is yours — when they disagree, §9), add placement on that theme. Returns compound where the signal already is |
908
825
  | `pre_emergence` | write that page this round — demand is ahead of the tools |
909
826
  | a `rank.movers` row whose impressions collapsed with a flat position, or a `gsc.pages.movers` row with `status` ≠ 200 | **technical round, no keyword work**: restore or redirect the URL, request indexing, re-read next window. Shape B (top of this file) — links and new pages do not fix a dead URL |
910
- | `gsc.pages.unseen` rows whose `index` is not indexed | **indexing round**: internal links into them, sitemap `lastmod`, indexing requests; do not judge their keywords until a window after they are indexed. This row is also the batch gate (§7.3 gate 4): last batch mostly indexed → ship the next family; mostly `Crawled - currently not indexed` → no new pages this round, and retire what Google has refused twice |
827
+ | `gsc.pages.unseen` rows whose `index` is not indexed | **indexing round**: internal links into them, sitemap `lastmod`, indexing requests; judge their keywords only a window after they are indexed. Also the batch gate (§7.3 gate 4): mostly indexed → ship the next family; mostly `Crawled - currently not indexed` → no new pages this round, retire what Google refused twice |
911
828
  | `rank.pending` non-empty | those words are not measured yet — no branch applies to them this round; do not read their zero as "missed" |
912
- | `authority_limited` | placement only **on that theme** another page on it will not move it (§6). The label is per keyword, not per site: production continues on every other theme. If every funded theme reads this way, the site is Shape C (top of this file): re-derive the ledger toward tool, long-tail and locale rows before pitching — and a site with no tools builds them first (§7.2) |
829
+ | `cells.missing` or `cells.queue` non-empty | **production round**: phrase the missing cells in their language, `--add-keywords` them, build the queue siblings of a verified family without a SERP; a new family through one `serp` first |
830
+ | `cells.retire` / `cells.cannibal` / `cells.defects` non-empty | **pruning round** for those pages: noindex or merge what two windows refused, collapse two pages on one intent into one, fix one-way hreflang (§7.3) |
831
+ | `authority_limited` | placement only **on that theme** — another page on it will not move it (§6). Per keyword, not per site: production continues on every other theme. Every funded theme reading this way is Shape C (top of this file): re-derive the ledger toward tool, long-tail and locale rows before pitching, building the tools first if the site has none (§7.2) |
913
832
  | `gsc.newQueries` non-empty | mini-discovery: fold them into the matrix, price the new cells, extend the tracked list if they survive the SERP check |
914
- | no movers two rounds running | the plan is stale, not slow — back to §1 and re-derive toward new page types; more waiting will not convert a flat line. The placement queue does not gate this: a queue that has waited on a human for two rounds is recorded as `blocked:` and handed over, and production goes on without it — placement is human-gated, building is not, and one must never hold the other (kunavo's four ready pitches held production for seven rounds) |
833
+ | no movers two rounds running | the plan is stale, not slow — back to §1 and re-derive toward new page types. The placement queue does not gate this: a queue that has waited on a human for two rounds is recorded as `blocked:` and handed over while production goes on — placement is human-gated, building is not, and one never holds the other (kunavo's four ready pitches held production for seven rounds) |
915
834
 
916
835
  **Rows are not exclusive.** A round takes every branch its read matches — a technical fix, a
917
- placement action and a production batch in the same session is the normal shape, not three
918
- rounds. `technical round` and `indexing round` say what to do *for those pages*; they never
919
- cancel the production step for the rest of the site.
836
+ placement action and a production batch in one session is the normal shape, not three rounds.
837
+ `technical round` and `indexing round` say what to do *for those pages*; they never cancel the
838
+ production step for the rest of the site.
920
839
 
921
840
  ### ④ Book the round
922
841
 
923
- Before the session ends, update `docs/seo/worksheet.md` (§3) — this is the step that makes the
924
- next round's allocation possible:
842
+ Before the session ends, update `docs/seo/worksheet.md` (§3):
925
843
 
926
- - **`page`** for anything shipped this round (`shipped:<url>`), **`placement`** for anything sent
927
- or accepted (`pitched:<target, date>` / `listed:<where>`). A pitch that got no reply is still
928
- a `pitched:` entry — the next session needs to know that target was already worked.
929
- - **The reason for anything you skipped**, as a skip row. That is what stops the next session
930
- re-buying a keyword this one already ruled out.
844
+ - **`placement`** for anything sent or accepted (`pitched:<target, date>` / `listed:<where>`);
845
+ pages are not booked by hand — `check.cells` reads them from the site. A pitch with no reply
846
+ is still a `pitched:` entry — that target was worked.
847
+ - **The reason for anything you skipped**, as a skip row what stops the next session re-buying
848
+ a keyword this one ruled out.
931
849
  - **New rows for whatever the read handed you** — `newQueries`, a keyword that just took a
932
850
  `signals` form — with their serp verdict once you have it.
933
- - **The batch table** (§3): for every shipped batch, `indexed` / `not indexed` from
934
- `gsc.pages.unseen` (found by `firstSeen`), and whether this window was another zero. This is
935
- the row the next round's batch gate and retire rule read.
851
+ - **The batch table** (§3): per shipped batch, `indexed` / `not indexed` from `gsc.pages.unseen`
852
+ (found by `firstSeen`), and whether this window was another zero what the next round's
853
+ batch gate and retire rule read.
936
854
 
937
- The stop-loss branch above ("no movers two rounds running") is answerable only if the previous
938
- round wrote down what it put in. The product does not track your side of the bet, deliberately:
939
- it cannot measure whether a pitch was sent, and a field it cannot measure is just a form for you
940
- to fill in. That state lives in the ledger or nowhere.
855
+ The stop-loss branch ("no movers two rounds running") is answerable only if the previous round
856
+ wrote down what it put in; the product records pages, not pitches (a field it cannot measure
857
+ would be a form for you to fill in), so that state lives in the ledger or nowhere.
941
858
 
942
859
  ### ⑤ Report the round
943
860
 
@@ -951,59 +868,53 @@ every row the round touched, one line each:
951
868
  | claude code preise | de-DE | official_wall | — | — | — | skip |
952
869
 
953
870
  `status` is one of `built` (shipped this round), `to build`, `exists` (a page already carries
954
- it), `skip` (with the reason). A `to build` row carries a blocker, and only three exist:
955
- `needs human` (a redirect, a send, money asked in one line, §7), `needs tool code` (a new
956
- client-side tool; name the session it ships in), `needs generator` (no family scaffold yet).
957
- "Analysis round", "next batch", "awaiting go-ahead" and "needs a SERP" are not blockers — a
958
- SERP is $0.02 inside the fuse and is bought on the spot and a row wearing one of those means
959
- the session is not finished: it goes back to step ⓪. Second, **placement** — target /
960
- page / status (`sent` / `drafted` / `blocked: needs human`). Then at most five lines of
961
- narrative. A report that is findings and no pages table is test 1 (§3) in its final form: the
962
- human cannot act on a paragraph. A round with an empty pages table says so *in* the table, with
963
- the cell count that justifies it kunavo round five delivered four findings, four
964
- opportunities and no table, and the three buildable families in its own prose went unbuilt.
871
+ it), `skip` (with the reason); `built` and `exists` are read off `check.cells`, not from memory.
872
+ A `to build` row carries one of three blockers: `needs human` (a redirect, a send,
873
+ money asked in one line, §7), `needs tool code` (a new client-side tool; name the session it
874
+ ships in), `needs generator` (no family scaffold yet). "Analysis round", "next batch",
875
+ "awaiting go-ahead" and "needs a SERP" are not blockers — a SERP is $0.02 inside the fuse,
876
+ bought on the spot — and a row wearing one means the session is not finished: back to step ⓪.
877
+ Second, **placement** — target / page / status (`sent` / `drafted` / `blocked: needs human`).
878
+ Then at most five lines of narrative. Findings with no pages table is test 1 (§3) in its final
879
+ form; an empty pages table says so *in* the table, with
880
+ the cell count that justifies it (kunavo round five: four findings, no table, three buildable
881
+ families in its own prose unbuilt).
965
882
 
966
883
  **Cadence**: SEO is a weeks-to-months system and the window `check` measures is 4 weeks wide —
967
- checking daily just re-reads the same window. Every two weeks is plenty. A round that re-reads
968
- an unchanged window must not re-judge *existing rows*: same window, no movers, no new queries →
969
- the P0s stand (tabledi 2026-09-02 re-ran discovery on the same data as 09-01 and flipped its
970
- P0a recommendation that flips on identical data is noise). **That rule never means no new
971
- cells.** Pricing a cell the ledger has never priced is not re-reading the window — the window
972
- has no opinion on it. Every round, whatever the window: count the ledger's unbuilt buildable
973
- rows against the site's cell space (§1.2: 100–150 for a full site); fewer than ten → this round
974
- enumerates (§1) and builds. kunavo, 2026-09-02, round five: same window, ledger exhausted,
975
- three markets never priced, a nine-cell family in prose — the round shipped zero pages and
976
- deferred the pricing for the third time, quoting this paragraph.
884
+ checking daily re-reads the same window; every two weeks is plenty. A round that re-reads an
885
+ unchanged window must not re-judge *existing rows*: same window, no movers, no new queries → the P0s
886
+ stand (tabledi, 2026-09-02, re-ran discovery on 09-01's data and flipped its P0: noise). **That rule
887
+ never means no new cells** the window has no opinion on a cell the ledger has never priced. Every
888
+ round, whatever the window: count the unbuilt buildable cells (`cells.queue`, `cells.missing`, the
889
+ ledger's unbuilt rows) against the site's cell space (§1.2: 100–150 for a full site); fewer than ten
890
+ this round enumerates (§1) and builds (kunavo, 2026-09-02, round five: ledger exhausted, three
891
+ markets never priced, a nine-cell family in prose — zero pages, quoting this paragraph).
977
892
 
978
893
  ---
979
894
 
980
895
  ## 11. Calibration discipline
981
896
 
982
- Every measurement here is a sample, not a census. Rank sampling is one fetch of a personalized,
983
- rotating results page. Traffic is adaptively sampled. AI-engine visibility measured by any tool
984
- is a sample of a non-deterministic system one independent evaluation found a major commercial
985
- tool undercounting by 40×.
986
-
987
- So: **promise time series against yourself, never absolute share.** "Our AI referrals went from
988
- 0 to 40 a month" is defensible. "We have 3% AI visibility" is not, no matter which tool printed
989
- it. Breaking this rule in customer-facing copy is a product-integrity failure, not a rounding
897
+ Every measurement here is a sample, not a census: rank sampling is one fetch of a personalized,
898
+ rotating results page; traffic is adaptively sampled; AI-engine visibility from any tool
899
+ samples a non-deterministic system (one independent evaluation found a major commercial tool
900
+ undercounting by 40×). So: **promise time series against yourself, never absolute share.** "Our
901
+ AI referrals went from 0 to 40 a month" is defensible; "we have 3% AI visibility" is not,
902
+ whichever tool printed it in customer-facing copy a product-integrity failure, not a rounding
990
903
  error.
991
904
 
992
- **The cases in this file are samples of one to three sites, and each varied one thing.** Before
993
- a case is cited for a rule, say what it varied, how many, and over which window: clize.ai's 72
994
- locale pages varied *page type* (their English originals earn the same nothing); kunavo's 199
995
- copies varied *translation* (identical, so Google collapsed them); tabledi's page-1 tools varied
905
+ **The cases in this file are samples of one to three sites, each varying one thing.** Cite a
906
+ case only with what it varied, how many, and over which window: clize.ai's 72 locale pages
907
+ varied *page type*; kunavo's 199 copies varied *translation*; tabledi's page-1 tools varied
996
908
  *age* (three years), not links; tabledi's 36 marketing locales were a day old when first read.
997
- A rule that survives only because its example was misread is a rule waiting to fail — three
998
- such misreadings were found in this file on 2026-09-02 and corrected.
909
+ A rule that survives only because its example was misread is waiting to fail — three such were
910
+ corrected here on 2026-09-02.
999
911
 
1000
912
  ---
1001
913
 
1002
914
  ## What this skill will not do
1003
915
 
1004
- Generate the content (that's your job — clize is the hands, you're the brain), submit to
1005
- directories or post to forums for you (manual, on purpose — though §6.2's outreach email loop
1006
- is fully in scope, because every send passes a human approval gate), or promise rankings. And
1007
- there is no automatic monitoring: measurement only pays off when someone can act on it, so a
1008
- recheck happens when you show up to run one. What it does count is pages: a round's deliverable
1009
- is shipped URLs and their index status, not a ledger (§3 test 6).
916
+ Generate the content (clize is the hands, you're the brain); submit to directories or post to
917
+ forums for you (manual, on purpose — §6.2's email loop is in scope because every send passes a
918
+ human approval gate); promise rankings; or monitor on its own (a recheck happens when you run
919
+ one: measurement pays off only when someone can act on it). It does count pages: a round's
920
+ deliverable is shipped URLs and their index status, not a ledger (§3 test 6).