Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions site/docs/reports/INDEX_POLICY_2026-10-25.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Toolify365 — search-index configuration inventory, 2026-10-25

## Verified by reading GitHub configuration (NOT live Google inspection)

- All tool definitions in `src/lib/tools/registry.ts`: **223**.
- Active locales in `src/lib/i18n/locales.ts`: **17**.
- Therefore generated tool-locale combinations: **3,791**.
- `CORE_TOOLS_BY_DEMAND`: **29** tools; default `INDEXED_LOCALES = ["en", "ja"]` means **58** core eligible tool-locale URLs.
- `INDEX_EXCEPTIONS`: **22** additional locale/slugs (Thai 4, Russian 4, Turkish 6, Arabic 5, French 1, Spanish 2).
- Total tool-locale URLs explicitly intended to be eligible for index: **80**.
- Tool-locale pages intentionally excluded by configuration: **3,711** (97.89%). This counts tool pages only, not the home, categories, directory, shared routes, or prompts.
- These 3,711 are **intentional noindex**, NOT 3,711 Google crawl/index failures.

The archived 50-URL Search Console inspection sample in `appdevelopsk/app-infra/gsc/latest.json` reported only 1 indexed and 36 crawled-not-indexed. Since the 50 exact URLs and their chosen indexable status were not available, do not equate the 36 with intentionally noindexed URLs; Google distinguishes these verdicts and requires per-URL inspection. Do not quote `1/50` as a site-wide indexing ratio.

New reproducible read-only commands from `site/`:

```sh
npm run audit:index-policy
npm run audit:index-policy -- --json
npm run audit:index-policy -- --urls
```

The script loads the actual locale registry and tool metadata, checks duplicate slugs, invalid exception slugs/locales, and that each per-tool hreflang locale list agrees with the indexable decision. It emits the exact 80 **intended** candidate tool URLs for later official Search Console URL Inspection. It never changes robots, meta-noindex, sitemaps, canonical, hreflang, deployed content or Google APIs.

## Prioritized diagnosis

1. Inspect exact `en/ja` **29 core pairs** and 22 exceptions with GSC URL Inspection (authenticated owner account). Record `PASS`/coverageState, lastCrawlTime, Google-selected canonical, declared canonical, robots/fetch status and referring sitemap for each.
2. Partition the prior 50 sample by **intended index eligibility** before making any "deindexing" statement. Without exact URLs, the 36 crawled-not-indexed cannot be attributed.
3. Compare 28-day finalized GSC impressions/clicks per 80 intended URL candidates and current public HTML after verified deployment. 2026-10-20..22 recent SMEPost GSC (free 3-day window) returned no opportunities for `https://toolify365.com/`; no inference of zero index coverage.
4. Improve tool-specific original utility and on-page examples before considering changes to the October 11 allowlist.
5. **Do not bulk change indexability/robots/sitemap/canonical before the prior 2026-12-06 freeze end without a new evidence-backed decision.** A code merge or a site: search is not URL Inspection evidence.

Note: the source inventory counts are accurate for this commit, not a forecast of what Google will index.
3 changes: 2 additions & 1 deletion site/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@
"report:calculate": "node scripts/calculate-ranking.mjs",
"postbuild": "node scripts/check-built-titles.mjs && node scripts/check-built-canonical.mjs && node scripts/check-built-descriptions.mjs",
"check:pressure": "node scripts/check-pressure-reference.mjs",
"check:currency": "node scripts/check-currency-rate-freshness.mjs"
"check:currency": "node scripts/check-currency-rate-freshness.mjs",
"audit:index-policy": "tsx scripts/report-index-policy.ts"
},
"dependencies": {
"@types/qrcode": "^1.5.6",
Expand Down
74 changes: 74 additions & 0 deletions site/scripts/report-index-policy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/**
* Read-only diagnosis of deliberately indexable tool/locale URLs.
* Does NOT call Google APIs, submit sitemaps, or change SEO directives.
* Usage: npm run audit:index-policy [-- --json] [-- --urls]
*
* These are *intended* robots/index candidates, never actual Google coverage.
*/
import { LOCALES, INDEXED_LOCALES } from "../src/lib/i18n/locales";
import { listTools, INDEXED_SLUGS, INDEX_EXCEPTIONS, isIndexableIn, indexableLocalesFor } from "../src/lib/tools/registry";

function inspect() {
const tools = listTools();
const all = tools.flatMap(tool => LOCALES.map(locale => ({
url: `https://toolify365.com/${locale}/tools/${tool.slug}`,
slug: tool.slug,
locale,
intendedIndex: isIndexableIn(locale, tool.slug)
})));
const allowed = all.filter(row => row.intendedIndex);
const byLocale = Object.fromEntries(LOCALES.map(l => [l, {
toolPages: tools.length,
intendedIndex: allowed.filter(x => x.locale === l).length,
intentionallyNoindex: tools.length - allowed.filter(x => x.locale === l).length
}]));
const invalid = [];
const slugs = tools.map(t=>t.slug);
if (new Set(slugs).size !== slugs.length) invalid.push("Duplicate tool slug");
for (const slug of INDEXED_SLUGS) if (!slugs.includes(slug)) invalid.push("Core slug absent from registry: "+slug);
for (const [locale, exceptions] of Object.entries(INDEX_EXCEPTIONS)) {
if (!LOCALES.includes(locale as (typeof LOCALES)[number])) invalid.push("Unknown exception locale: "+locale);
for(const slug of exceptions) if(!slugs.includes(slug)) invalid.push("Unknown exception tool: "+locale+"/"+slug);
if(new Set(exceptions).size !== exceptions.length) invalid.push("Duplicate exceptions in "+locale);
}
for (const tool of tools) {
const expected = indexableLocalesFor(tool.slug);
for (const locale of LOCALES) {
if (isIndexableIn(locale, tool.slug) !== expected.includes(locale)) {
invalid.push("Mismatch registry indexability: "+locale+"/"+tool.slug);
}
}
}
if (invalid.length) throw Error(invalid.join(" | "));
return {
runAtUtc: new Date().toISOString(),
warning: "This is a SOURCE CONFIGURATION INTENT audit, NOT a GSC URL Inspection response. 3711 intentionally noindexed pages must not be counted as Google exclusions.",
fullToolLocalePages: all.length,
tools: tools.length,
locales: LOCALES.length,
coreTools: INDEXED_SLUGS.size,
indexedCoreLocales: INDEXED_LOCALES,
explicitlyIndexedExceptionPairs: Object.values(INDEX_EXCEPTIONS).reduce((n,v)=>n+v.length,0),
indexCandidates: allowed.length,
deliberatelyNoindex: all.length - allowed.length,
byLocale,
urls: allowed.map(x=>x.url)
};
}

try {
const report=inspect();
if (process.argv.includes("--json")) {
console.log(JSON.stringify(report,null,2));
} else if (process.argv.includes("--urls")) {
console.log(report.urls.join("\n"));
} else {
console.log("Toolify intended index candidates: "+report.indexCandidates+"/"+report.fullToolLocalePages+
" tool-locale pages; intentionally noindex "+report.deliberatelyNoindex);
console.table(report.byLocale);
console.log("Use --urls to get exact 80 intended inspection targets. Actual Google status requires GSC URL Inspection.");
}
} catch (e) {
console.error("[index-policy] FAIL: "+String(e));
process.exitCode=1;
}
Loading