# AI Visibility and Local Authority Runbook Companion to https://fc-build-spec-a5aaf279.vercel.app/annex.md section L. This file holds the human protocols. The spec gates what a build may ship; nothing here can be enforced by a build, which is exactly why it needs owners and a cadence. Fortitude Creative. Last updated 2026-09-25. **Read this first.** When someone asks an assistant "best AC repair in Phoenix," the answer is assembled mostly from sources the client does not own: Google Business Profile, review platforms, aggregator listings, local listicles, forum threads. Section K prepares the one surface the client controls. This runbook works the rest. If only one of the two ever gets done, the site will be beautifully structured and uncited. --- ## 1. Off-site authority ### Google Business Profile GBP is not a posting chore. For local queries it is the primary retrieval surface, and the profile is read more often than the website. | Action | Cadence | Owner | |---|---|---| | Posts | Weekly | CSR / dispatcher | | Q&A monitoring and answers | Within 24 hours | CSR / dispatcher | | Photo uploads | Matched to the project pipeline | Content coordinator | | Review responses | Within 48 hours, every review, including the good ones | CSR / dispatcher | | Category, service list, hours, service area accuracy | Monthly check | SEO Lead | ### Review velocity - **Target: 10 or more new Google reviews per rolling 90 days**, per location. - Velocity matters more than the lifetime total. A 4.9 with nothing new in eight months reads as a business that stopped, both to a human and to a model summarizing recency. - Every review answered within 48 hours. Responses are public text about the business, and they get read by the same systems that read everything else. ### NAP audit - **Quarterly minimum**, across Google, Yelp, Angi, BBB, Apple Maps, Bing Places, and any industry directory the client appears in. - **GBP is canonical.** Discrepancies propagate outward from it, never inward. - On completion, set `napLastVerifiedAt` on each LocationHub (annex L.2). That timestamp is the evidence the audit happened. Setting it without doing the audit is the one failure mode this whole control has, so it belongs to a named person, not a rotating task. - **Owner:** SEO Lead. ### Getting into the sources that get cited The listicles, "best of" roundups, and directory pages that rank for `best hvac [city]` are what assistants summarize. Appearing in them is the off-site equivalent of ranking. - Identify the top 10 pages currently ranking for the primary commercial queries per market. - Determine which accept submissions, which are pay-to-play, and which are editorial. - Pursue the editorial and free ones first, and record the outcome. Note honestly which are paid, because a paid placement is an ad, and the client should know which is which. - **Owner:** SEO Lead, quarterly. --- ## 2. The measurement loop ### Monthly citation panel Run the same queries, the same way, every month. Consistency is what makes the data readable. - **Query list:** minimum 10 service x city intersections covering primary revenue. Include at least `best [service] [city]`, `emergency [service] [city]`, and `[service] near me` framed for the market. - **Assistant panel:** ChatGPT with browsing, Perplexity, Gemini, Claude, Bing Copilot. - **Log to the `ai_visibility_tests` table** defined in annex L.5, one row per assistant per query. - **Record what was cited, not only whether the client appeared.** The cited sources are the finding. Appearance is one bit; the source list tells you where the next quarter's work goes. - **Screenshots:** store the full response where legal review permits, hash-only where it does not. Resolve this with counsel before the first run rather than after. - **Owner:** SEO Lead. Roughly two hours a month. It does not scale to every client by hand, which is the argument for automating it with Playwright once the manual version has proven what to capture. **Required query classes (v4.1).** Before any new surface enters the sitemap, the panel must cover: - *Planning intent:* "cost to replace AC in [city]", "new furnace estimate [city]", "HVAC replacement cost [city]". These are cost-intent queries, which are allowed and wanted; the pages answering them carry cost factors and no numbers. - *Model specific,* one set per published EquipmentModelPage: "[brand] [model] reviews", "is [brand] [model] reliable", "[brand] vs [competitor] [system type]". - *Specials:* "hvac specials [city]", "[company name] coupons". The runbook owner signs off on the expanded query set before the surfaces ship. ### What "appeared" means Decide once and keep it stable, or month-to-month comparison is meaningless: - **appeared** = the business is named in the answer body. - **link_present** = the answer includes a clickable link to the client's domain. - **sentiment** = the tone of the mention. `hallucination` is its own value and is not a synonym for negative: an invented service area or a fabricated price is a different problem from a bad review, and it escalates differently. --- ## 3. Analysis and feedback ### Quarterly review - Read the cited sources across every run. The question is not whether the client appeared; it is **which sources the assistants trusted when they did, and which competitors occupied those sources when they did not.** - That reading produces the next quarter's off-site targets. This is the loop's actual output. - Proposals to demote a section K requirement come out of this review, with the evidence attached, and land as a normal pull request against the annex and the `kRequirementStatus` config together (annex L.6). No automated demotion. A human signs it. ### Negative mention and hallucination escalation - An assistant citing a negative review, or inventing a problem that does not exist, escalates within 24 hours. - Hallucinations get corrected at the source where possible: fix the underlying fact on the site and in GBP, then re-run the query the following month to see whether it cleared. - **Owner:** SEO Lead escalates; Jason decides whether it becomes a PR matter. --- ## 4. Roles and governance | Responsibility | Owner | Cadence | Delegable | Automatable | |---|---|---|---|---| | Runbook execution overall | SEO Lead | Ongoing | No | No | | GBP posts, Q&A, review responses | CSR / dispatcher | Weekly / 24-48h | Yes | Reminders only | | Photo pipeline | Content coordinator | With project capture | Yes | Partly | | NAP audit and `napLastVerifiedAt` | SEO Lead | Quarterly | Yes | No | | Citation panel execution | SEO Lead | Monthly | Yes, to an analyst | Query submission only | | `approvedModels[]` maintenance | SEO Lead | Quarterly | **No** | **No** | | Model page exemption approvals | SEO Lead | As raised | **No** | **No** | | L.6 quarterly analysis | SEO Lead | Quarterly | **No** | Shortlist generation only | | Review count incident response | SEO Lead | 8 business hours | DevOps as backup | No | | Crawler UA list, referrer domains, GBP thresholds | SEO Lead with DevOps | Quarterly | Yes | Partly | | Specials lifecycle and coupon expiry | Marketing Ops | Weekly | Yes | Yes | | Places API cron, review badge CI, job reliability | DevOps | Ongoing | Yes | Yes | | Cost-guide prose, WCAG compliance, model page content | Content Lead | Ongoing | Yes | No | | Escalation decisions | Jason | As raised | No | No | The three rows in bold are the irreducible core. Everything else can be handed off or scripted. ### Review count negative-delta incident ```yaml reviewCountNegativeDelta: threshold: 0.20 alertChannel: [pagerduty-seo, slack-#seo-alerts] reviewOwner: seoLead # DevOps is backup slaHours: 8 # business hours frozenScope: review_count_value_only # deployments are NOT blocked resolutionOptions: accept_decline: "Investigate cause, document in the incident log, release the new value" legitimate_drop: "Location closed or reviews purged; rebaseline and release" data_error: "Places API glitch; keep the last known good value" ``` Without a written resolution path the first alert produces confusion and an ad-hoc bypass, and the bypass becomes the process. Pick one of the three, write the reason, move on. ### Job reliability All nightly jobs — orphan check, review aggregation, coupon expiry, license expiry — complete in under 15 minutes. **Two consecutive missed executions page on-call.** A nightly job that silently stops is worse than no job, because the absence of alerts reads as health. ### Capacity, stated so nobody is surprised | Role | Requirement | |---|---| | SEO Lead | 0.6 FTE continuous | | Marketing Ops | +0.3 FTE continuous, from v4.2: promo badges, financing content, manager endorsements | | Legal | +0.05 FTE quarterly, from v4.2: financing block review, warranty and guarantee language | **Shared staffing across clients is permitted up to 150% total allocation per role.** Past that, onboarding another client requires added headcount or contract hours first, not optimism. ### Who actually performs these roles This runbook names seven functions: SEO Lead, Marketing Ops, Content Lead, Content Coordinator, DevOps, Legal, and an engineering on-call rotation. **Read that as a scope of work, not as an org chart the client is expected to staff.** A three-truck HVAC company has a dispatcher, an office manager and an owner who answers the phone. It will never hire a content coordinator or run a PagerDuty rotation. That is not a flaw in this specification; it is the reason the specification is worth paying someone to run. The functions are real and the work is real — the question is only who performs it. | Function | Performed by the agency | Performed by the client | |---|---|---| | Architecture, templates, CI gates, schema | Yes | No | | `approvedModels[]`, tier assignment, exemptions | Yes | No | | Citation panel, NAP audit, quarterly analysis | Yes | No | | Nightly jobs, cache purge, widget monitoring | Yes | No | | GBP posts, Q&A, review responses | Optional, often better shared | Dispatcher or office manager | | **Photographing the job on site** | **No. Cannot be.** | **The technician, always** | | Legal review of credit terms | Their counsel, or the mode stays off | Their counsel | Only one row cannot be bought: a technician standing in a plant room with a phone. Everything else in this runbook is a service. That single row is also the constraint the entire architecture rests on, which is why the project-capture workflow is worth more attention than any other item here. ### Role mapping when one person holds several This runbook names seven roles: SEO Lead, Marketing Ops, Content Lead, Content Coordinator, DevOps, Legal, and an engineering on-call rotation. That is a description of **functions, not headcount**. In a small agency one person holds several, and the spec works fine that way as long as the mapping is written down per client rather than assumed. What does not survive compression, whoever holds it: - The three non-delegable judgement calls above stay with one named person. - **An on-call rotation of one person is not a rotation.** If P1 booking-widget response is promised to a client, either the rotation genuinely exists or the SLO should say business hours and mean it. A written 24/7 promise backed by one phone is worse than an honest business-hours commitment. - Legal review is the one function that cannot be absorbed internally. N.6's `specific` financing mode requires an actual reviewer; if there is none, the mode stays off, which is the recommended configuration anyway. **Management acknowledgement is required before v4.2 activates.** If these roles are not resourced, the conversion components ship empty and the escalation chains generate noise nobody acts on, which is worse than not having them: an alert that is always firing trains everyone to ignore alerts. **The SEO Lead role is scoped at 0.6 FTE minimum.** Below that, the section L SLAs cannot be met and should not be promised. Three things in this runbook cannot be delegated or automated: maintaining `approvedModels[]`, approving model page exemptions, and interpreting the quarterly review. Query submission can be automated and the citation panel can be delegated to an analyst; the judgement cannot. **If the SEO Lead lacks capacity,** the split that survives contact with a busy week: GBP and reviews move to CSR entirely, the citation panel moves to Marketing Ops, and the NAP audit stays with SEO because it feeds a publish gate. Do not split the NAP audit from the person who owns the timestamp. --- ## Deferred: branded program taxonomy **Eligibility trigger, monitored by the SEO Lead:** site-wide, 100 or more published Projects **and** 10 or more active technician profiles, sustained for 30 days before the v4.3 spec process opens. Recommended additionally: at least 3 service areas at tier-1 density, 6+ projects each, so the program has geographic spread rather than one busy city carrying the claim. Not in v4.2. Revisit when a service area has **100 or more published projects and 10 or more active technician profiles**. A branded guarantee or named program needs operational history behind it to be credible. Shipping the taxonomy before the history exists produces ghost entities: named programs with nothing under them, which read as marketing language to a reader and as thin templated pages to a crawler. --- ## runbook.yaml The build reads this file and fails when `owner` or `reviewCadence` is null (annex L.0). ```yaml owner: reviewCadence: quarterly citationPanelCadence: monthly napAuditCadence: quarterly lastReviewedAt: ```