insights: coming-soon page; block AI training crawlers; fix stale e2e
CI / ci (push) Successful in 1m34s
CI / ci (push) Successful in 1m34s
- /insights/ is a reader-facing Coming soon page; developer cards removed - robots.txt: Disallow GPTBot, ClaudeBot, Google-Extended, CCBot, Applebot-Extended, meta-externalagent, Bytespider. Search and AI answer crawlers stay allowed. Corrects the old Google-Extended comment: it does not affect Search or AI Overviews. - e2e: assert the real headings and the header Services link (48/48)
This commit is contained in:
1 parent
e07cb8545e
commit
04e0c4d9cd
4 files changed
+43
-61
No files matched your search
+15
-24
@@ -28,7 +28,7 @@ Status legend: `[ ]` open · `[x]` done · `[?]` needs verification · 🛑 owne
|
|||||||
| Search | Google Search Console domain property verified; sitemap submitted and fetched by Googlebot |
|
| Search | Google Search Console domain property verified; sitemap submitted and fetched by Googlebot |
|
||||||
| Mail | MXroute. SPF pass, DKIM pass (selector `x`), DMARC `p=none` — mail-tester 9.5/10 |
|
| Mail | MXroute. SPF pass, DKIM pass (selector `x`), DMARC `p=none` — mail-tester 9.5/10 |
|
||||||
| `npm run build` / `typecheck` / `seo:lint` | green, 21 pages |
|
| `npm run build` / `typecheck` / `seo:lint` | green, 21 pages |
|
||||||
| `npm run test:e2e` | 44 passed / 4 failed — stale assertions, see §2.1 |
|
| `npm run test:e2e` | **48/48 green** |
|
||||||
|
|
||||||
### Traffic path
|
### Traffic path
|
||||||
```
|
```
|
||||||
@@ -79,32 +79,21 @@ discovered 2026-10-23.
|
|||||||
- [ ] Durable fix in the `gitea` ansible role: disable live-restore on that VM, or restart the
|
- [ ] Durable fix in the `gitea` ansible role: disable live-restore on that VM, or restart the
|
||||||
runner after dockerd restarts (systemd `PartOf=`/`ExecStartPost` hook).
|
runner after dockerd restarts (systemd `PartOf=`/`ExecStartPost` hook).
|
||||||
|
|
||||||
### 1.4 `/insights/` ships empty, with developer-facing copy 🛑
|
### 1.4 `/insights/` ✅ 2026-10-23
|
||||||
`src/pages/insights/index.astro` shows two cards written for a developer ("Publishing path",
|
Now a reader-facing "Coming soon" page (hero + contact CTA); the developer-facing cards are gone.
|
||||||
"RSS support") and a hero calling the section a "Future publishing home". The section is in the
|
It stays in the nav. When the first real article lands, restore a listing on this page.
|
||||||
primary nav with zero articles.
|
|
||||||
- [ ] 🛑 Ship it or not.
|
|
||||||
- [ ] If yes: delete both note-cards and rewrite the hero as reader-facing copy.
|
|
||||||
- [ ] If no: drop it from the primary nav and exclude the route from the sitemap.
|
|
||||||
|
|
||||||
### 1.5 Privacy policy review 🛑
|
### 1.5 Privacy policy ✅ 2026-10-23
|
||||||
`/privacy/` went live 2026-10-23, drafted from what the site actually does (contact form via
|
`/privacy/` reviewed and accepted by the owner. No consent banner (owner's call).
|
||||||
Formspree, Umami, GA4 with cookies, server/security logs).
|
Anything added to `src/components/Analytics.astro` must be disclosed on `/privacy/`.
|
||||||
- [ ] 🛑 Owner review of the text. It is a legal document.
|
|
||||||
- [ ] 🛑 Consent banner: GA4 sets cookies. Strictly, EU/UK visitors need opt-in consent; most
|
|
||||||
US-focused small-business sites run with a privacy policy only. Owner's call. Umami needs
|
|
||||||
neither.
|
|
||||||
- Anything added to `src/components/Analytics.astro` must be disclosed on `/privacy/`.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 2. Should fix
|
## 2. Should fix
|
||||||
|
|
||||||
### 2.1 e2e suite is red — stale assertions, not a regression
|
### 2.1 e2e suite ✅ green 2026-10-23 — 48/48
|
||||||
4 of 48 fail (2 tests × desktop/mobile). Both assert **copy the exact-copy work correctly removed**:
|
The stale assertions (invented copy removed by the exact-copy work) now check the real headings
|
||||||
- `tests/site.spec.ts:63` waits for a link named `Explore services`; the homepage CTA is `All services`.
|
and use the header Services link; the homepage body has no direct `/services/` link.
|
||||||
- `tests/site.spec.ts:93` waits for a heading matching `/Focused expertise/`, gone from `/focus-areas/`.
|
|
||||||
- [ ] Update both tests to current copy; get back to green so the suite is trustworthy.
|
|
||||||
|
|
||||||
### 2.2 Repo hygiene
|
### 2.2 Repo hygiene
|
||||||
Commit `9f1cbca` committed ~50 `.playwright-mcp/` screenshots/snapshots plus a 2.8 MB
|
Commit `9f1cbca` committed ~50 `.playwright-mcp/` screenshots/snapshots plus a 2.8 MB
|
||||||
@@ -122,11 +111,13 @@ Commit `9f1cbca` committed ~50 `.playwright-mcp/` screenshots/snapshots plus a 2
|
|||||||
- [x] **Canonical host** — `www` (2026-10-23). Apex 301s via Traefik middleware in `k8s/ingress.yaml`.
|
- [x] **Canonical host** — `www` (2026-10-23). Apex 301s via Traefik middleware in `k8s/ingress.yaml`.
|
||||||
- [x] **Analytics** — Umami + GA4 side by side (2026-10-23).
|
- [x] **Analytics** — Umami + GA4 side by side (2026-10-23).
|
||||||
- [ ] 🛑 **Contact details** — confirm `804-332-6618` / `info@bluecapstrategies.com` are final.
|
- [ ] 🛑 **Contact details** — confirm `804-332-6618` / `info@bluecapstrategies.com` are final.
|
||||||
- [ ] 🛑 **AI training-bot policy** — `GPTBot` and `ClaudeBot` are **Allow: /** in
|
- [x] **AI training-bot policy** — training crawlers blocked (2026-10-23): GPTBot, ClaudeBot,
|
||||||
`public/robots.txt`, with a ready-to-uncomment `Disallow: /`. The site is now crawlable.
|
Google-Extended, CCBot, Applebot-Extended, meta-externalagent, Bytespider. Search and
|
||||||
|
AI answer/search crawlers (Googlebot, Bingbot, OAI-SearchBot, Claude-SearchBot, …) stay allowed.
|
||||||
- [ ] 🛑 **Brad Rodgers bio + credentials + portrait** — gates `Person` schema, the About
|
- [ ] 🛑 **Brad Rodgers bio + credentials + portrait** — gates `Person` schema, the About
|
||||||
buildout, and principal-led E-E-A-T/GEO positioning.
|
buildout, and principal-led E-E-A-T/GEO positioning.
|
||||||
- [ ] 🛑 **Real insights articles** — no fabricated or unreviewed AI content (see §1.4).
|
- [ ] 🛑 **Real insights articles** — no fabricated or unreviewed AI content. `/insights/` is
|
||||||
|
"Coming soon" until the first one exists (§1.4).
|
||||||
- [ ] 🛑 **Social profiles** — provide real profiles or omit the footer block.
|
- [ ] 🛑 **Social profiles** — provide real profiles or omit the footer block.
|
||||||
- [ ] 🛑 **Proof modules / representative engagements** — no fabricated client work.
|
- [ ] 🛑 **Proof modules / representative engagements** — no fabricated client work.
|
||||||
|
|
||||||
|
|||||||
+21
-13
@@ -1,8 +1,6 @@
|
|||||||
# BlueCap Strategies robots.txt — see docs/seo-aeo-optimization.md §5
|
# BlueCap Strategies robots.txt — see docs/seo-aeo-optimization.md §5
|
||||||
# Policy: allow classic search + AI answer/search crawlers for maximum discoverability and
|
# Policy: allow classic search + AI answer/search crawlers for maximum discoverability and
|
||||||
# answer-engine citation. Training-crawler policy (GPTBot, ClaudeBot, Google-Extended) is an
|
# answer-engine citation. Model-TRAINING crawlers (GPTBot, ClaudeBot, Google-Extended, …) are BLOCKED (owner decision, 2026-10-23).
|
||||||
# owner decision — currently ALLOWED for maximum reach. To opt out of model training, uncomment
|
|
||||||
# the "Disallow: /" lines in the training-crawler block below.
|
|
||||||
|
|
||||||
# --- Classic search engines ---
|
# --- Classic search engines ---
|
||||||
User-agent: Googlebot
|
User-agent: Googlebot
|
||||||
@@ -27,19 +25,29 @@ Allow: /
|
|||||||
User-agent: PerplexityBot
|
User-agent: PerplexityBot
|
||||||
Allow: /
|
Allow: /
|
||||||
|
|
||||||
# Google-Extended controls Gemini + Google AI Overviews (this is also a training signal for
|
# --- AI model-training crawlers — blocked (owner decision, 2026-10-23) ---
|
||||||
# Google — treated as answer-visibility here; move to the training block to opt out).
|
|
||||||
User-agent: Google-Extended
|
|
||||||
Allow: /
|
|
||||||
|
|
||||||
# --- AI model-training crawlers (owner decision — allowed by default) ---
|
|
||||||
User-agent: GPTBot
|
User-agent: GPTBot
|
||||||
Allow: /
|
Disallow: /
|
||||||
# Disallow: /
|
|
||||||
|
|
||||||
User-agent: ClaudeBot
|
User-agent: ClaudeBot
|
||||||
Allow: /
|
Disallow: /
|
||||||
# Disallow: /
|
|
||||||
|
User-agent: CCBot
|
||||||
|
Disallow: /
|
||||||
|
|
||||||
|
User-agent: Applebot-Extended
|
||||||
|
Disallow: /
|
||||||
|
|
||||||
|
User-agent: meta-externalagent
|
||||||
|
Disallow: /
|
||||||
|
|
||||||
|
User-agent: Bytespider
|
||||||
|
Disallow: /
|
||||||
|
|
||||||
|
# Google-Extended is Google's opt-out for Gemini training/grounding only. Google Search and AI
|
||||||
|
# Overviews are governed by Googlebot (allowed above), so blocking this does not affect search.
|
||||||
|
User-agent: Google-Extended
|
||||||
|
Disallow: /
|
||||||
|
|
||||||
# --- Everything else ---
|
# --- Everything else ---
|
||||||
User-agent: *
|
User-agent: *
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import ContactCta from "@components/ContactCta.astro";
|
|||||||
import { breadcrumbSchema, pageSchema } from "@utils/schema";
|
import { breadcrumbSchema, pageSchema } from "@utils/schema";
|
||||||
|
|
||||||
const description =
|
const description =
|
||||||
"A prepared future publishing section for BlueCap Strategies articles, essays, case studies, market notes, and announcements.";
|
"Articles, analysis, and updates from BlueCap Strategies are coming soon.";
|
||||||
---
|
---
|
||||||
|
|
||||||
<BaseLayout
|
<BaseLayout
|
||||||
@@ -22,26 +22,9 @@ const description =
|
|||||||
>
|
>
|
||||||
<PageHero
|
<PageHero
|
||||||
eyebrow="Insights"
|
eyebrow="Insights"
|
||||||
title="Future publishing home for BlueCap Strategies"
|
title="Coming soon"
|
||||||
lead="This section is prepared for articles, essays, case studies, market notes, and announcements when BlueCap migrates thought leadership from Substack, Medium, or other channels onto its own domain."
|
lead="Articles, analysis, and updates from BlueCap Strategies will be published here."
|
||||||
image="/assets/live-site/img_0067.jpg"
|
image="/assets/live-site/img_0067.jpg"
|
||||||
/>
|
/>
|
||||||
<section class="insights-shell">
|
|
||||||
<article class="note-card">
|
|
||||||
<h2>Publishing path</h2>
|
|
||||||
<p>
|
|
||||||
Future posts can be added as Markdown or MDX in <code>src/content/insights</code> with
|
|
||||||
typed frontmatter for title, description, publish date, modified date, tags, and optional
|
|
||||||
canonical URL.
|
|
||||||
</p>
|
|
||||||
</article>
|
|
||||||
<article class="note-card">
|
|
||||||
<h2>RSS support</h2>
|
|
||||||
<p>
|
|
||||||
RSS is available at <a href="/rss.xml">/rss.xml</a>. The feed is ready for future article
|
|
||||||
imports even though no public posts are published yet.
|
|
||||||
</p>
|
|
||||||
</article>
|
|
||||||
</section>
|
|
||||||
<ContactCta />
|
<ContactCta />
|
||||||
</BaseLayout>
|
</BaseLayout>
|
||||||
+4
-4
@@ -64,14 +64,14 @@ test("desktop navigation and CTA links are clickable", async ({ page }) => {
|
|||||||
await page.setViewportSize({ width: 1440, height: 900 });
|
await page.setViewportSize({ width: 1440, height: 900 });
|
||||||
await page.goto("/");
|
await page.goto("/");
|
||||||
|
|
||||||
await page.getByRole("link", { name: "Explore services" }).click();
|
await page.getByRole("banner").getByRole("link", { name: "Services", exact: true }).first().click();
|
||||||
await expect(page).toHaveURL(/\/services\/$/);
|
await expect(page).toHaveURL(/\/services\/$/);
|
||||||
await expect(page.getByRole("heading", { name: /Advisory services/ })).toBeVisible();
|
await expect(page.getByRole("heading", { level: 1, name: "Services" })).toBeVisible();
|
||||||
|
|
||||||
await page.goto("/");
|
await page.goto("/");
|
||||||
await page.getByRole("link", { name: "Request a consultation" }).first().click();
|
await page.getByRole("link", { name: "Request a consultation" }).first().click();
|
||||||
await expect(page).toHaveURL(/\/contact\/$/);
|
await expect(page).toHaveURL(/\/contact\/$/);
|
||||||
await expect(page.getByRole("heading", { name: /Get in touch/ })).toBeVisible();
|
await expect(page.getByRole("heading", { level: 1, name: "Contact Us" })).toBeVisible();
|
||||||
});
|
});
|
||||||
|
|
||||||
test("service and focus-area learn more links are wired to detail pages", async ({ page }) => {
|
test("service and focus-area learn more links are wired to detail pages", async ({ page }) => {
|
||||||
@@ -98,7 +98,7 @@ test("mobile menu opens and navigates", async ({ page }) => {
|
|||||||
await expect(page.locator(".mobile-nav nav")).toBeVisible();
|
await expect(page.locator(".mobile-nav nav")).toBeVisible();
|
||||||
await page.locator(".mobile-nav").getByRole("link", { name: "Focus Areas" }).click();
|
await page.locator(".mobile-nav").getByRole("link", { name: "Focus Areas" }).click();
|
||||||
await expect(page).toHaveURL(/\/focus-areas\/$/);
|
await expect(page).toHaveURL(/\/focus-areas\/$/);
|
||||||
await expect(page.getByRole("heading", { name: /Focused expertise/ })).toBeVisible();
|
await expect(page.getByRole("heading", { level: 1, name: "Core Focus Areas" })).toBeVisible();
|
||||||
});
|
});
|
||||||
|
|
||||||
test("contact form validates required, invalid, and valid paths", async ({ page }) => {
|
test("contact form validates required, invalid, and valid paths", async ({ page }) => {
|
||||||
|
|||||||
Reference in new issue
Block a user