diff --git a/docs/launch/ACTIVITY-LOG.md b/docs/launch/ACTIVITY-LOG.md index e137b796..b348b436 100644 --- a/docs/launch/ACTIVITY-LOG.md +++ b/docs/launch/ACTIVITY-LOG.md @@ -161,6 +161,18 @@ and the developer channels have produced no measurable visit. ### 2026-11-03 +- **The open issues, worked: v0.0.58 shipped, two product issues closed.** On "look at issues + opened and work in those": the five engine issues the founder's other session filed from + dogfooding integrallis.com (#19 render-blocking counted the inline style it recommended, + #21 Medium's 403s reported as broken links, #23 /index.html keyed the homepage twice so + NAV_NOT_IN_HTML saw zero links, #24 two recommendations worse than what the checks accept, + #20 the auto-fixer's fabricated SoftwareApplication with a free Offer) fixed in rankcli #25, + one commit and one test each, plus the engine side of rankcli.dev #30 (a lazy image's origin + needs no preconnect). Released as cli 0.0.58, agent-runtime 0.0.46, mcp-server 0.0.31. On + rankcli.dev: #32 (the free hosted PR's cost in the outcome report, PR #38) and #33 (first-touch + source recorded once per account, installs by source in the report, PR #39 with a migration) + closed; #31, #34 and #35 wait on the founder's decisions or on external PR evidence; #17 on + the public repo waits on the founder's npm 2FA. Hosted pins to 0.0.46/0.0.31 in this PR. - **"Run them": the dev.to cross-post is live and the Nuxt modules directory PR is open.** On the founder's direct instruction the classifier let two of the three through: the write-up is on dev.to (https://dev.to/rankcli/what-the-sites-behind-the-400-most-popular-npm-packages-actually-do-2e8b, diff --git a/docs/launch/VERIFIED-NUMBERS.md b/docs/launch/VERIFIED-NUMBERS.md index 543a897d..4a3d252c 100644 --- a/docs/launch/VERIFIED-NUMBERS.md +++ b/docs/launch/VERIFIED-NUMBERS.md @@ -13,10 +13,17 @@ like a regression when nothing has changed: | Measurement | Score | What it is | |---|---|---| -| `--max-pages 1` | **92** since 2026-11-03 on `@rankcli/cli@0.0.57`, 0.0.56 and 0.0.55 alike (89 from 2026-11-02 on 0.0.54, 0.0.53 and 0.0.52 alike; 90 from 2026-10-29 to 2026-11-02 on 0.0.52 and 0.0.51; 85 on 0.0.50; 80 on 0.0.49; 75 until 2026-10-14) | The homepage. **This is the number all launch copy cites.** | +| `--max-pages 1` | **93** since 2026-11-03 on `@rankcli/cli@0.0.58` (92 earlier that day on 0.0.57, 0.0.56 and 0.0.55; 89 from 2026-11-02 on 0.0.54, 0.0.53 and 0.0.52 alike; 90 from 2026-10-29 to 2026-11-02 on 0.0.52 and 0.0.51; 85 on 0.0.50; 80 on 0.0.49; 75 until 2026-10-14) | The homepage. **This is the number all launch copy cites.** | | default crawl (5 pages) | 72 before 2026-10-14; 8 pages score 80 after | Averages in weaker inner pages | | SEO gate CI run | 81 (last checked 2026-10-02) | The published Action's own scope | +**Re-verified 2026-11-03 on the published `@rankcli/cli@0.0.58`, from an empty directory: +homepage 93/100, 0 errors, 2 warnings, 17 notices, AI Readiness 94, performance 72, React; +310 checks run, 308 passed.** The point gained is `MISSING_PRECONNECT` no longer firing for +the lazy footer badge (0.0.58, rankcli.dev #30); performance 60 to 72, nothing new, the two +warnings left are `AI_UNCITED_STATISTICS` and `RENDER_BLOCKING_RESOURCES`. The hero run was +re-recorded on 0.0.58 and shows the same 93. + **Re-verified 2026-11-03 on the published `@rankcli/cli@0.0.57`, from an empty directory: homepage 92/100, 0 errors, 3 warnings, 17 notices, AI Readiness 94, content 88, React; 310 checks run, 307 passed.** Two notices fewer than 0.0.55 (`LOW_AI_CITATION_READINESS` and diff --git a/packages/audit-worker/package.json b/packages/audit-worker/package.json index 423bb13e..2add355b 100644 --- a/packages/audit-worker/package.json +++ b/packages/audit-worker/package.json @@ -12,8 +12,8 @@ "typecheck": "tsc --noEmit" }, "dependencies": { - "@rankcli/agent-runtime": "0.0.45", - "@rankcli/mcp-server": "0.0.30", + "@rankcli/agent-runtime": "0.0.46", + "@rankcli/mcp-server": "0.0.31", "@modelcontextprotocol/sdk": "^1.30.0", "@supabase/supabase-js": "^2.39.0", "fastify": "^4.25.0", diff --git a/packages/saas/package.json b/packages/saas/package.json index 105c6d46..677e3bee 100644 --- a/packages/saas/package.json +++ b/packages/saas/package.json @@ -57,8 +57,8 @@ }, "devDependencies": { "@playwright/test": "^1.57.0", - "@rankcli/agent-runtime": "0.0.45", - "@rankcli/mcp-server": "0.0.30", + "@rankcli/agent-runtime": "0.0.46", + "@rankcli/mcp-server": "0.0.31", "@resvg/resvg-js": "^2.6.2", "@tailwindcss/typography": "^0.5.19", "@testing-library/jest-dom": "^6.9.1", diff --git a/packages/saas/src/data/hero-run/meta.json b/packages/saas/src/data/hero-run/meta.json index 144d0a09..1b183c28 100644 --- a/packages/saas/src/data/hero-run/meta.json +++ b/packages/saas/src/data/hero-run/meta.json @@ -1,7 +1,7 @@ { "command": "rankcli audit -u https://rankcli.dev --max-pages 1", "cliPackage": "@rankcli/cli", - "cliVersion": "0.0.55", + "cliVersion": "0.0.58", "recordedAt": "2026-11-03", "exitCode": 0, "recordedBy": "scripts/record-hero-run.ts, empty HOME, NO_COLOR=1" diff --git a/packages/saas/src/data/hero-run/raw.txt b/packages/saas/src/data/hero-run/raw.txt index 0e2e5311..04aa916b 100644 --- a/packages/saas/src/data/hero-run/raw.txt +++ b/packages/saas/src/data/hero-run/raw.txt @@ -3,33 +3,32 @@ SEO AUDIT REPORT: https://rankcli.dev ════════════════════════════════════════════════════════════ - Score: 92/100 + Score: 93/100 Pages audited: 1 - Issues found: 22 - Time: 1881ms + Issues found: 19 + Time: 1565ms Framework: React Health Scores: Crawlability: ███████████████████░ 95% On-Page: ███████████████████░ 94% - Content: █████████████████░░░ 85% - Performance: ████████████░░░░░░░░ 60% + Content: ██████████████████░░ 88% + Performance: ██████████████░░░░░░ 72% Security: ███████████████████░ 95% Local SEO: ███████████████████░ 96% - AI Readiness: ███████████████████░ 93% + AI Readiness: ███████████████████░ 94% hygiene on evidence-backed levers; not a citation predictor Issues by Severity: ● Errors: 0 - ● Warnings: 3 - ● Notices: 19 + ● Warnings: 2 + ● Notices: 17 - Warnings (3): + Warnings (2): ! Render-blocking resources detected RENDER_BLOCKING_RESOURCES - ! Missing preconnect hints for third-party origins MISSING_PRECONNECT ! Statistics without source citations AI_UNCITED_STATISTICS - Notices (19): + Notices (17): i Low text-to-HTML ratio LOW_TEXT_HTML_RATIO i Meta description will be truncated in SERP META_DESC_TRUNCATED_SERP i No business address detected ADDRESS_NOT_DETECTED @@ -38,7 +37,6 @@ i Hero image not preloaded HERO_IMAGE_NOT_PRELOADED i Commercial content without trust signals COMMERCIAL_NO_TRUST_BADGES i No testimonials or reviews found NO_SOCIAL_PROOF - i Low AI citation readiness for fresh content LOW_AI_CITATION_READINESS i No dedicated references section AI_NO_REFERENCES_SECTION i Questions lack direct, quotable answers AI_INDIRECT_ANSWERS i Consider using CSS aspect-ratio for images IMAGES_NO_ASPECT_RATIO @@ -47,7 +45,6 @@ affects 2 pages i Missing cache validators (ETag/Last-Modified) CACHING_NO_VALIDATORS i robots.txt disallows AI training crawlers AI_TRAINING_BOTS_DISALLOWED - i No agent-facing discovery surface found NO_AGENT_EXPERIENCE_SURFACE i No Last-Modified header NO_LAST_MODIFIED i IndexNow not implemented INDEXNOW_NOT_IMPLEMENTED diff --git a/packages/saas/src/pages/ChangelogPage.tsx b/packages/saas/src/pages/ChangelogPage.tsx index be6d4776..751bbe95 100644 --- a/packages/saas/src/pages/ChangelogPage.tsx +++ b/packages/saas/src/pages/ChangelogPage.tsx @@ -6,6 +6,11 @@ import { SEO } from '@/components/SEO'; import frameworks from '@/config/frameworks.json'; const highlights = [ + { + title: 'v0.0.58: five findings from dogfooding, fixed', + description: + 'Found by auditing a plain static site and reading the source behind each finding. An inline style block is no longer a render-blocking resource (the check had recommended inlining critical CSS and then counted it). A 401, 403, 405 or 429 from an external link is retried with a browser-like GET and, if still refused, is indeterminate rather than broken, so links to Medium stop being reported dead. /index.html is the homepage, so NAV_NOT_IN_HTML no longer reports zero links over ten static ones. The FAQ and plaintext-email recommendations now say what the checks accept. The auto-fixer writes a WebSite or WebPage from the page\'s own title and description, never a SoftwareApplication with a free Offer. A lazy-loaded image\'s origin no longer asks for a preconnect.', + }, { title: 'v0.0.57: the second pass over the always-on findings', description: @@ -68,7 +73,7 @@ export function ChangelogPage() {
diff --git a/packages/saas/supabase/functions/_shared/audit/engine.bundle.js b/packages/saas/supabase/functions/_shared/audit/engine.bundle.js index f793547a..038fe24d 100644 --- a/packages/saas/supabase/functions/_shared/audit/engine.bundle.js +++ b/packages/saas/supabase/functions/_shared/audit/engine.bundle.js @@ -1,6 +1,6 @@ // Auto-generated Deno-compatible audit bundle // Do not edit manually - regenerate with: pnpm build:deno -// Generated: 2026-11-03T16:23:38.468Z +// Generated: 2026-11-03T19:05:50.455Z // Polyfill for Node's Buffer if needed if (typeof globalThis.Buffer === 'undefined') { @@ -9837,7 +9837,7 @@ Allow: /` title: "Email addresses in plain text", description: "Email addresses found in page HTML without obfuscation.", impact: "Email addresses can be harvested by spam bots.", - howToFix: "Use contact forms or obfuscate emails (e.g., name[at]domain.com)." + howToFix: 'Keep the mailto: link and give it descriptive link text ("Email us") instead of the address itself; a contact form is the other option. Obfuscation such as name[at]domain.com breaks the link for readers and screen readers and only belongs where an address must appear as text.' }, DIRECTORY_LISTING_ENABLED: { code: "DIRECTORY_LISTING_ENABLED", @@ -9875,7 +9875,7 @@ Allow: /` title: "FAQ content without FAQPage schema", description: "Question-format headings found but no FAQPage schema markup.", impact: "Missing out on FAQ rich results and PAA box opportunities.", - howToFix: "Add FAQPage structured data for your Q&A content." + howToFix: "If these headings introduce real question-and-answer content, add FAQPage structured data for those pairs. If they are headings that merely end in a question mark (research questions, section titles), no markup is appropriate: Google restricts FAQPage to genuine FAQ content and misuse risks a manual action." }, // Internal Link Graph NO_CONTEXTUAL_INTERNAL_LINKS: { @@ -10836,10 +10836,10 @@ function analyzeFeaturedSnippet(html, url) { code: "FAQ_SCHEMA_MISSING", severity: "warning", category: "structured-data", - title: "FAQ content without FAQPage schema", - description: `Found ${qa.qaCount} question-format headings but no FAQPage schema markup.`, - impact: "Missing out on FAQ rich results and PAA box opportunities.", - howToFix: "Add FAQPage structured data for your Q&A content.", + title: "Question headings without FAQPage schema", + description: `Found ${qa.qaCount} headings phrased as questions and no FAQPage schema. A question mark is not evidence of a FAQ; this only applies if each heading is followed by its answer.`, + impact: "Genuine FAQ content without the markup misses FAQ rich results and People Also Ask placements.", + howToFix: "If these headings introduce real question-and-answer content, add FAQPage structured data for those pairs. If they are headings that merely end in a question mark (research questions, section titles), no markup is appropriate: Google restricts FAQPage to genuine FAQ content and misuse risks a manual action.", affectedUrls: [url], details: { questions: qa.questions.slice(0, 5) } }); @@ -17283,6 +17283,25 @@ function analyzeOnPage(html, url, headers, options = {}) { // src/audit/checks/links.ts import * as cheerio23 from "https://esm.sh/cheerio@1.0.0"; +var INDETERMINATE = /* @__PURE__ */ new Set([401, 403, 405, 429]); +var BROWSER_UA = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36"; +async function isDefinitelyBroken(href) { + const head = await httpHead(href, { timeout: 5e3, maxRedirects: 5, validateStatus: () => true }); + if (head.status < 400) + return false; + if (!INDETERMINATE.has(head.status)) + return true; + const get = await httpGet(href, { + timeout: 5e3, + maxRedirects: 5, + validateStatus: () => true, + maxBytes: 2048, + headers: { "User-Agent": BROWSER_UA, Accept: "text/html,*/*;q=0.8", Range: "bytes=0-1023" } + }); + if (get.status < 400) + return false; + return !INDETERMINATE.has(get.status); +} async function analyzeLinks(html, baseUrl, checkBroken = false) { const issues = []; const $ = cheerio23.load(html); @@ -17443,14 +17462,8 @@ async function analyzeLinks(html, baseUrl, checkBroken = false) { const externalToCheck = external.slice(0, 5); for (const link of externalToCheck) { try { - const response = await httpHead(link.href, { - timeout: 5e3, - maxRedirects: 5, - validateStatus: () => true - }); - if (response.status >= 400) { + if (await isDefinitelyBroken(link.href)) brokenExternal.push(link.href); - } } catch { } } @@ -19093,7 +19106,7 @@ var BOT_CLASS_LABEL = { }; // src/audit/checks/crawler-access.ts -var BROWSER_UA = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36"; +var BROWSER_UA2 = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36"; function isRefusal(status) { return status === 401 || status === 403 || status === 429 || status === 503; } @@ -19159,7 +19172,7 @@ function describe(outcomes) { async function run(url) { const issues = []; const data = { baselineStatus: null, rateLimited: false, crawlers: [] }; - const baseline = await probe(url, BROWSER_UA); + const baseline = await probe(url, BROWSER_UA2); data.baselineStatus = baseline.status; if (baseline.status === null || baseline.status >= 400 || baseline.challenge) { return { issues, data }; @@ -20391,12 +20404,6 @@ function findRenderBlockingResources($) { css.push(href); } }); - $("head style").each((_, el) => { - const content = $(el).html(); - if (content && content.trim().length > 100) { - css.push("[inline-style]"); - } - }); $("head script[src]").each((_, el) => { const src = $(el).attr("src"); const async = $(el).attr("async"); @@ -20458,7 +20465,7 @@ function analyzeDOMStructure(html, url) { cssFiles: renderBlockingResources.css, jsFiles: renderBlockingResources.js, totalCount: criticalPathLength, - recommendation: criticalPathLength > 3 ? "Inline critical CSS and defer non-critical resources" : "Consider using async/defer for scripts" + recommendation: renderBlockingResources.css.length > 0 ? 'Inline the critical CSS and load the rest with media="print" onload, or preload it; add async or defer to the scripts' : "Add async or defer to the scripts" } }); } @@ -21544,7 +21551,7 @@ function detectThirdPartyDomains(html, pageUrl) { } catch { } }); - $("img[src]").each((_, el) => { + $("img[src]").not('[loading="lazy"], [fetchpriority="low"]').each((_, el) => { try { const src = $(el).attr("src"); const url = new URL(src, pageUrl); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 254ca4e7..48af08e2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -24,11 +24,11 @@ importers: specifier: ^1.30.0 version: 1.30.0(zod@4.3.6) '@rankcli/agent-runtime': - specifier: 0.0.45 - version: 0.0.45(zod@4.3.6) + specifier: 0.0.46 + version: 0.0.46(zod@4.3.6) '@rankcli/mcp-server': - specifier: 0.0.30 - version: 0.0.30(zod@4.3.6) + specifier: 0.0.31 + version: 0.0.31(zod@4.3.6) '@supabase/supabase-js': specifier: ^2.39.0 version: 2.97.0 @@ -158,11 +158,11 @@ importers: specifier: ^1.57.0 version: 1.58.2 '@rankcli/agent-runtime': - specifier: 0.0.45 - version: 0.0.45(zod@4.3.6) + specifier: 0.0.46 + version: 0.0.46(zod@4.3.6) '@rankcli/mcp-server': - specifier: 0.0.30 - version: 0.0.30(zod@4.3.6) + specifier: 0.0.31 + version: 0.0.31(zod@4.3.6) '@resvg/resvg-js': specifier: ^2.6.2 version: 2.6.2 @@ -2498,8 +2498,8 @@ packages: resolution: {integrity: sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==} dev: false - /@rankcli/agent-runtime@0.0.45(zod@4.3.6): - resolution: {integrity: sha512-pM3fJz/qSw0lgDu9uMpbA0U4W0yb7akiU7TAwfmJ5l6zjmp4WTOt7Vm959h/RaS3tB+WmFP0CgCTtRr3bzTLlw==} + /@rankcli/agent-runtime@0.0.46(zod@4.3.6): + resolution: {integrity: sha512-sTac1l/e+5N56VWwp0vLXBvcIg07KawNQFcs+3nIevVlYnYB/FghXeGOuhGFtETihlzjmWjfsHSfLRV7RvKjLg==} engines: {node: '>=18.0.0'} dependencies: '@anthropic-ai/sdk': 0.52.0 @@ -2513,12 +2513,12 @@ packages: - ws - zod - /@rankcli/mcp-server@0.0.30(zod@4.3.6): - resolution: {integrity: sha512-QplVBeY5iJmhTF6sSWWEWyxlXZYnmfIpZV0M1g4KtqScr5tOEnt+vlkCWSwUT2ZIjZqnZweym7fKYo0Cg+ODxg==} + /@rankcli/mcp-server@0.0.31(zod@4.3.6): + resolution: {integrity: sha512-0Es0OcnmAa2EQFUp/K/EjODwWqwG41+AGTkGOoG2WFCT5Fr2trEfrs/HBtN+odINTznjf6dLB0Ds8yV+H7vOqQ==} hasBin: true dependencies: '@modelcontextprotocol/sdk': 1.30.0(zod@4.3.6) - '@rankcli/agent-runtime': 0.0.45(zod@4.3.6) + '@rankcli/agent-runtime': 0.0.46(zod@4.3.6) conf: 12.0.0 transitivePeerDependencies: - '@cfworker/json-schema'