Dev Log

Backlog 0002 — teaser system, bookkeeper hide, surveyor stat removal, Zack portrait, AI bot tracking

· Claude Opus 4.7 (1M context) · Bot
teaserintelligenceseoai-visibilitycareersteamstatsredaction

What was done

Item 7 — Zack Reese portrait

  • Copied .tmp/0002_26_05_04_backlog/zach.png to src/assets/team/zack.png (renamed to match the canonical first-name convention used by other team portraits — shane.png, kelli.png, etc.).
  • Wired zack-reese into the portraitImages map in src/pages/about/index.astro and src/pages/about/[slug].astro.

Item 1 — Hide the filled bookkeeper role

  • Removed the role from the roles array in src/pages/careers/index.astro so the talent funnel no longer advertises it.
  • Removed it from the careers list in src/pages/search.astro.
  • Set noindex={true} on the page itself so direct visits still render but the URL drops out of search indexes. BaseLayout already exposed a noindex prop — no layout changes needed.

Item 3 — Remove “Subdivisions as surveyor” card

  • Deleted the .number-card block from src/pages/projects/index.astro and src/pages/about/bailey.astro.
  • Left baileyStats.lifetime.subdivisionsAsSurveyor (value 88) in src/data/bailey-stats.ts intact — source-of-truth value from landproDATA, may be referenced again later.

Item 5 — Remove label legend

  • Deleted the <p class="label-key"> legend (“CHAMPION ≥90% rezone approval rate · CAUTIOUS ≥75% · …”) from src/components/CityPage.astro (covers Meridian and Nampa) and src/pages/service-areas/ada-county/boise/index.astro.
  • Per-member colored badges (CHAMPION, CAUTIOUS, etc.) themselves stay visible — only the explanatory legend is gone, fitting the Item 4 teaser philosophy.

Item 4 — Teaser / content-lock on intelligence pages

The big piece. Approach: server-side redaction with depth-narrative copy. Real proprietary values never reach the rendered HTML; bots and LLMs read narrative that signals Bailey’s intelligence depth without publishing the numbers.

New components

  • src/components/Teaser.astro — inline redacted span with unlock CTA. Used in table cells and stat positions where a single value used to live. Accepts city, label, placeholder, optional href. Defaults the CTA to /contact/?topic=city-intelligence&city=<slug>.
  • src/components/TeaserBlock.astro — paragraph-level variant with depth narrative + unlock CTA. Used to replace tactical-advice paragraphs (Commissioner Intelligence, Fire Station alert).

CityPage.astro — added a teaseMetrics?: { city: string } prop. When set, the shared component swaps:

  • numbers.appTypes[].rate cells → <Teaser> per row
  • numbers.denialReasons[].count numbers → <Teaser> per card
  • commissionerIntel.items[] bodies → wrapped in <TeaserBlock> using the body field as the depth-narrative slot
  • recent.stats[].value numbers → <Teaser> per stat

This keeps the per-city page files almost data-only — no JSX duplication for the redaction switchover.

New contact-form topiccity-intelligence:

  • Added a sixth form variant to src/pages/contact.astro with name, phone, email, company, “city of interest”, parcel APN, and “what you most want to know” fields. Reuses the existing WEB3FORMS_KEY_PROJECTS API key, routes to projects@.
  • Added city-intelligence to the validTopics allowlist in the topic-switcher script.
  • Added URL ?city=<slug> handling — auto-stamps a hidden field and prefills the visible “city of interest” text input (title-cased: boise → “Boise”, garden-city → “Garden City”).
  • This is now the unlock destination for every Teaser CTA.

Per-page redactions:

  • Boise — staff paragraph, numbers table rates, denial counts, Commissioner Intelligence (rewritten as 7 TeaserBlocks per commissioner), recent-activity stats, FAQ answer specifics, and Why-Bailey rate. Hero snapshot + At-a-glance kept visible per ask.md.
  • Meridian — uses teaseMetrics. Stripped trailing parenthetical percentages from PZ concerns. Rewrote commissionerIntel headings (no trailing , 88.4%) and bodies (depth narrative). Rewrote staffHtml to remove the specific 93.3%. Teased the infrastructure-squeeze alert specifics ($1.8M, 4,500). Rewrote FAQ answers and whyBailey body.
  • Nampa — uses teaseMetrics. Stripped trailing parenthetical percentages from Council member concerns (per ask.md line 24: "Fire Station, Traffic, Density (100%)""Fire Station, Traffic, Density"). Rewrote commissionerIntel headings and bodies. Rewrote staffHtml. Teased the Fire Station alert specifics (response-time threshold, $1,567 fee benchmark, named application IDs). Rewrote FAQ answers and whyBailey body.
  • RS4 Nampa article — teased the three hero stats (95% / 112d / 3.8), the three voting-table rates (96/94/98%), and the three time-to-approval stats (112d / 28d / 42d). Pseudonymized commissioner table label changed from “Confirm with city before publishing” to “Shared with active project teams.” Aligned the missing-block CTA from topic=parcel-analysis to topic=city-intelligence. Quick-answer prose, “the setup”, and “Why the window might not stay open” left intact (article hook + qualitative framing).

Approval gate: the depth-narrative copy in Commissioner Intelligence, Fire Station alert, and Why-Bailey paragraphs asserts Bailey capabilities. Per CLAUDE.md (“anything asserting Bailey numbers is queued for Ryan”), this prototype copy needs Ryan review before any production push.

Item 2 — Cloudflare AI Crawl Control monitoring

  • Confirmed Bailey’s authoritative AI-bot signal is Cloudflare’s AI Crawl Control panel (not GA4 — AI crawlers don’t execute JS).
  • Captured the 2026-05-04 baseline: 240 AI requests in 24h, GPTBot dominant (109 allowed), homepage most-crawled.
  • Decision flag: the panel’s “Managed robots.txt” toggle adds AI-training opt-out directives. Enabling it would directly contradict the year-long AI-visibility SEO plan. Documented as a do-not-enable in .tmp/seo/ai-bot-tracking.md and saved as a feedback memory for future sessions.
  • Cloudflare’s dashboard window is 24h (Free/Pro/Business). The only retention escape is the GraphQL Analytics API. Decided not to run a manual snapshot cadence — the automated path (Cloudflare Worker on a scheduled trigger → ZIG/R2) is the goal. Deferred to .tmp/backlog.md.
  • Added an ai-crawler-monitoring row to Phase 6 (Measurement) of src/content/seo-plan/items.json with a “pending automation” note so the row doesn’t generate manual-snapshot busywork before the Worker exists.
  • Updated seo-plan/items.json lastUpdated to 2026-05-04.

Why

User-driven backlog at .tmp/0002_26_05_04_backlog/ask.md. The through-line for Items 4–6 is: Bailey wants AI search systems and human visitors to perceive the firm as data-driven and intelligence- powered, but the actual proprietary numbers (approval rates, commissioner playbooks, fire-station thresholds, dollar benchmarks) are the value Bailey sells on intelligence calls — not free public material. The Teaser system threads that needle: bots and LLMs read narrative depth signals; specific values are gated behind a contact form.

Items 1, 3, 5, 7 are routine site upkeep flagged in the same backlog batch. Item 2 closes a research question about whether GA4 can distinguish AI traffic (no, but Cloudflare AI Crawl Control already does) and locks in the right Cloudflare configuration plus the forward path for retention beyond 24 hours.

Files affected

Created:

  • src/components/Teaser.astro
  • src/components/TeaserBlock.astro
  • src/assets/team/zack.png
  • .tmp/seo/ai-bot-tracking.md
  • .tmp/backlog.md (deferred backlog file — first entry: AI Crawl Control automation)
  • .tmp/0002_26_05_04_backlog/plan.md (the plan that drove this execution)

Modified:

  • src/components/CityPage.astro (added Teaser/TeaserBlock imports, teaseMetrics prop, conditional rendering for table rates, denial counts, commissioner intel bodies, recent stats; removed label-key legend)
  • src/pages/about/index.astro (Zack portrait import + map entry)
  • src/pages/about/[slug].astro (Zack portrait import + map entry)
  • src/pages/about/bailey.astro (removed surveyor-stat card)
  • src/pages/projects/index.astro (removed surveyor-stat card)
  • src/pages/careers/index.astro (removed bookkeeper from roles)
  • src/pages/careers/bookkeeper-office-manager.astro (added noindex={true})
  • src/pages/search.astro (removed bookkeeper sitemap entry)
  • src/pages/contact.astro (added city-intelligence form variant + topic, URL ?city handling)
  • src/pages/service-areas/ada-county/boise/index.astro (Teaser + TeaserBlock imports, redactions in staff paragraph, numbers table, denial cards, Commissioner Intelligence, recent stats, FAQs, Why Bailey; removed label-key legend; added city-intelligence CTA)
  • src/pages/service-areas/ada-county/meridian/index.astro (Teaser import, stripped PZ concern parens, rewrote commissionerIntel headings + bodies, rewrote staffHtml, teased infra-squeeze alert specifics, rewrote FAQs + whyBailey, added teaseMetrics)
  • src/pages/service-areas/canyon-county/nampa/index.astro (Teaser import, stripped Council concern parens, rewrote commissionerIntel headings + bodies, rewrote staffHtml, teased Fire Station alert specifics, rewrote FAQs + whyBailey, added teaseMetrics)
  • src/pages/dev-iq/land-use-intelligence/rs4-nampa.astro (Teaser
    • TeaserBlock imports, teased hero stats, voting-table rates and notes column, time-to-approval stats; aligned missing-block CTA to topic=city-intelligence)
  • src/content/seo-plan/items.json (added ai-crawler-monitoring row to Phase 6, bumped lastUpdated)

Memory updates (outside the codebase):

  • reference_cloudflare_ai_crawl_control.md (new — pointer to the panel + 24h limit + GraphQL escape)
  • feedback_cloudflare_managed_robots_off.md (new — do not enable the AI-training opt-out toggle)
  • MEMORY.md index updated with both pointers

Verification

npm run build — 198 pages built, no errors. Spot-checked rendered HTML in dist/:

  • service-areas/ada-county/boise/index.html: contains 12 Teaser components, 0 occurrences of 81.4% (the redacted staff follow rate)
  • service-areas/canyon-county/nampa/index.html: 1 occurrence of 94.8% remaining — both in the hero DATA SNAPSHOT and At-a-glance prose, both intentionally kept visible per ask.md
  • service-areas/ada-county/meridian/index.html: 1 occurrence of 9.9 percentage remaining — in the At-a-glance prose, also intentionally kept
  • careers/bookkeeper-office-manager/index.html: <meta name="robots" content="noindex,nofollow"> shipped
  • careers/index.html and search/index.html: 0 occurrences of “Bookkeeper”

UI not visually verified in a browser — content/structure changes only, but spot rendering of the Teaser styles in dev would be a useful pre-publish step before Ryan reviews the narrative copy.

Feedback