You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 3916697
Browse filesBrowse the repository at this point in the historyBrowse files
Copy file name to clipboardExpand all lines: docs/operations.md
+2-2Lines changed: 2 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -68,11 +68,11 @@ The landing page and the free tools also exist in Hungarian and Spanish, each at
68
68
69
69
[`scripts/llms-full.mjs`](../scripts/llms-full.mjs) then writes `dist/llms-full.txt`: `llms.txt` followed by the visible text of `/`, `/about`, `/best-ai-for-debate` and `/press`, read from their built HTML. It is a build output, not a file in `public/`.
70
70
71
-
[`scripts/check-site.mjs`](../scripts/check-site.mjs) runs next and fails the build when an internal link, a `#fragment`, a sitemap URL or an `llms.txt` URL does not resolve (it applies the `vercel.json` redirects and rewrites), when JSON-LD does not parse or carries HTML entities, when a FAQPage question is not visible on its page, when the home page's entity graph has an unresolved `@id`, a `WebSite` or `SoftwareApplication` not named for the product, or no `Organization.sameAs`, when a page's `publisher` or `about` names an `@id` the home page does not define, when an indexed page other than `/terms`, `/privacy`, and `/expocit/sources` lacks its question H2 (`#short-answer`) as the first H2 (a page whose H1 is already that question may instead put the answer in a `#short-answer` paragraph before the first H2), when a page's first heading is not its H1 or a heading skips a level (H1 to H3), when an image has no alt text, a button has no name or a form field has no label, or when a page's `hreflang` links do not resolve, leave out the page itself or `x-default`, disagree with `<html lang>`, or differ from the set on a page they name.
71
+
[`scripts/check-site.mjs`](../scripts/check-site.mjs) runs next and fails the build when an internal link, a `#fragment`, a sitemap URL or an `llms.txt` URL does not resolve (it applies the `vercel.json` redirects and rewrites), when JSON-LD does not parse or carries HTML entities, when a FAQPage question is not visible on its page, when the home page's entity graph has an unresolved `@id`, a `WebSite` or `SoftwareApplication` not named for the product, or no `Organization.sameAs`, when a page's `publisher` or `about` names an `@id` the home page does not define, when an indexed page other than `/terms`, `/privacy`, and `/expocit/sources` lacks its question H2 (`#short-answer`) as the first H2 (a page whose H1 is already that question may instead put the answer in a `#short-answer` paragraph before the first H2), when a page's first heading is not its H1 or a heading skips a level (H1 to H3), when an image has no alt text, a button has no name or a form field has no label, when two indexed pages share a `<title>`, or when a page's `hreflang` links do not resolve, leave out the page itself or `x-default`, disagree with `<html lang>`, or differ from the set on a page they name.
72
72
73
73
[`scripts/check-links.mjs`](../scripts/check-links.mjs) runs after it and fails the build when a sitemap page other than `/terms`, `/privacy` and `/expocit/sources` has fewer than 3 inbound links from other sitemap pages, or when the home page links to fewer than 15 distinct sitemap pages. `node scripts/check-links.mjs --report` prints every count after a build. The home page reaches the guides and tools through [`GuideHub.tsx`](../src/components/landing/GuideHub.tsx).
74
74
75
-
The guide pages in `public/<slug>/index.html` are generated, not hand-edited: run `python3 scripts/generate_seo_content.py` and commit its output. The same command writes the seven comparison and prep pages from [`scripts/seo_comparison_pages.py`](../scripts/seo_comparison_pages.py), each with its own layout, and lists them in `llms.txt`. Those pages link to `/best-ai-for-debate` while that page is still a separate draft; [`scripts/check-site.mjs`](../scripts/check-site.mjs) allows that one missing path until its file exists. Short pages live in its `PAGES` list; pages with long-form copy, their own highlight-card descriptions, and their own FAQs (which also feed the page's FAQPage JSON-LD) live in [`scripts/seo_guides.py`](../scripts/seo_guides.py). Each page's "Related" block shows up to six pages from its own topic cluster and one from each of two other clusters, picked from `CLUSTERS`; every page in `PAGES` must sit in exactly one cluster, and the generator stops when one does not. Paragraphs also get up to three in-body links from `LINK_PHRASES`, specific phrases first; `python3 scripts/generate_seo_content.py --links` lists the links each page got. A guide entry can set a later `modified` date for that page alone; no page is dated earlier than `CONTENT_DATE`, which covers the copy every guide shares, including the related and in-body links, so move it when `CLUSTERS` or `LINK_PHRASES` change. Sections hold paragraphs and `h3`, `steps`, `list`, `table` and `example` blocks, plus a `speech_times` block that builds the speech-times table from the free timer's formats in [`src/lib/free-tools/formats.ts`](../src/lib/free-tools/formats.ts), so the guide and the timer cannot disagree; a guide's `definition` (question, term, text) renders a definition list under the short answer and a `DefinedTerm` in its JSON-LD; paragraphs, list items and table cells can hold Markdown-style links to a site path or, for a primary source, an `https://` URL. Every guide needs FAQs of its own in `seo_guides.py`; the generator refuses a page without them, so no two pages share boilerplate questions. [`src/test/seo/guide-content.test.ts`](../src/test/seo/guide-content.test.ts) fails when a guide has fewer than 700 words outside its related and About blocks, or when a sentence longer than 60 characters appears on more than three guides.
75
+
The guide pages in `public/<slug>/index.html` are generated, not hand-edited: run `python3 scripts/generate_seo_content.py` and commit its output. The same command writes the seven comparison and prep pages from [`scripts/seo_comparison_pages.py`](../scripts/seo_comparison_pages.py), each with its own layout, and lists them in `llms.txt`. Those pages link to `/best-ai-for-debate` while that page is still a separate draft; [`scripts/check-site.mjs`](../scripts/check-site.mjs) allows that one missing path until its file exists. Short pages live in its `PAGES` list; pages with long-form copy, their own highlight-card descriptions, and their own FAQs (which also feed the page's FAQPage JSON-LD) live in [`scripts/seo_guides.py`](../scripts/seo_guides.py). Each page's "Related" block shows up to six pages from its own topic cluster and one from each of two other clusters, picked from `CLUSTERS`; every page in `PAGES` must sit in exactly one cluster, and the generator stops when one does not. Paragraphs also get up to three in-body links from `LINK_PHRASES`, specific phrases first; `python3 scripts/generate_seo_content.py --links` lists the links each page got. A guide entry can set a later `modified` date for that page alone; no page is dated earlier than `CONTENT_DATE`, which covers the copy every guide shares, including the related and in-body links, so move it when `CLUSTERS` or `LINK_PHRASES` change. Sections hold paragraphs and `h3`, `steps`, `list`, `table` and `example` blocks, plus a `speech_times` block that builds the speech-times table from the free timer's formats in [`src/lib/free-tools/formats.ts`](../src/lib/free-tools/formats.ts), so the guide and the timer cannot disagree; a guide's `definition` (question, term, text) renders a definition list under the short answer and a `DefinedTerm` in its JSON-LD; paragraphs, list items and table cells can hold Markdown-style links to a site path or, for a primary source, an `https://` URL. A guide can set a `disclosure` line, shown under its byline, and a numbered list: `items` (name, URL) pairs that become an `ItemList` in its JSON-LD, each matched in order by an `h3` that starts "1. Name"; a title with `{item_count}` gets the real count, and the generator stops when the headings and `items` disagree. Every guide needs FAQs of its own in `seo_guides.py`; the generator refuses a page without them, so no two pages share boilerplate questions. [`src/test/seo/guide-content.test.ts`](../src/test/seo/guide-content.test.ts) fails when a guide has fewer than 700 words outside its related and About blocks, or when a sentence longer than 60 characters appears on more than three guides.
76
76
77
77
Every guide opens with the reader's main question as its first H2 and an answer of at most 100 words, kept in [`scripts/seo_answers.py`](../scripts/seo_answers.py); the generator refuses a page without one or with a longer answer. Each guide shows visible "Published" and "Updated" dates (`PUBLISHED_DATE` or a `published` key, and the `modified` date) that match its Article JSON-LD. Prices and plan facts are stated "as of" the month in `factsCheckedOn` in `src/config/site.json`; move that date when you recheck them, and the pricing page's About block, `llms.txt` and the landing page follow. Every other guide has a one-line About that links to the landing page and pricing instead of repeating the plan facts. Copy in `seo_guides.py` and `seo_answers.py` that names the month itself (prices and competitor facts) needs the same edit: search those files for "As of". The generator also writes `public/llms.txt`, the plain summary for AI agents. `public/robots.txt` allows AI crawlers by name in their own group, which repeats the private-route rules because a crawler that matches a named group ignores `*`.
0 commit comments