Pages are titled with the category a buyer searches for, not the name we call them internally
Affects: app/platform/cpq/page.tsx, app/platform/fms/page.tsx, app/platform/roi/page.tsx, app/pricing/page.tsx, app/solutions/page.tsx, app/integrations/page.tsx, app/fsm/dispatch/page.tsx, app/fsm/mobile/page.tsx, app/fsm/portal/page.tsx, components/fsm/workspace-heading.tsx (new), lib/constants.ts (FOOTER_COLUMNS), lib/corrections.ts (C-007).
The problem
D-107 fixed the homepage's title and D-108 fixed the canonicals, and after both of them Search Console reported 27 pages indexed against a sitemap of 134. The 27 are the right ones — every marketing route that matters is in the index. The site is findable by name.
It is not findable by category. Read the titles the site was shipping and the reason is not subtle:
| Route | Title before | What a buyer types | | --- | --- | --- | | /platform/cpq | CPQ Engine — parametric quoting that can't be wrong | "CPQ software for contractors" | | /platform/fms | FMS Dispatch — every van, every skill tag, every minute | "field service management software" | | /platform/roi | ROI model — quantify your operational advantage | "CPQ ROI calculator" | | /pricing | Enterprise pricing | "CPQ software pricing" | | /solutions | Industry solutions | "software for trade contractors" | | /integrations | Integrations | "CPQ QuickBooks integration" |
"FMS Dispatch" is what the navigation calls that page and what everyone here calls it in conversation. Nobody outside the building has ever typed it. The same is true of "CPQ Engine", and "Integrations" on its own is a word that belongs to every B2B site ever built.
None of this needed new claims to fix. SITE_CONFIG.keywords has published "enterprise CPQ software", "field service management software", "CPQ ROI calculator" and "vertical SaaS for trade contractors" the whole time; the homepage <h1> has read "CPQ & Field Service Management for specialty trade contractors" since D-107; the site-wide SoftwareApplication node declares applicationSubCategory: "CPQ & Field Service Management Software". The vocabulary was already on the site. It was in the fields a search engine weighs least and absent from the two it weighs most.
What was decided
Each page's <title>, the first clause of its description, and its <h1> lead with the category the page belongs to, and the line that made the page memorable follows the dash rather than being replaced by it. /platform/cpq reads "CPQ software for trade contractors — parametric quoting that can't be wrong": both halves, in the order a stranger needs them.
Every figure, every caveat, and every interpolated constant below the fold is untouched. Nothing was added that the page did not already support.
The three workspace routes had no <h1> at all
/fsm/dispatch, /fsm/mobile and /fsm/portal are server components that mount a client workspace, and that is the whole file. FsmShell renders a <header> and a <nav>; the workspaces start at <h2>. So all three served a document with no <h1> anywhere in it — a heading outline beginning at level two, under a page whose only prose was the chrome disclaimer.
Search Console suggests this cost something: two of the three are "Discovered — currently not indexed", never crawled.
components/fsm/workspace-heading.tsx is a server component — no "use client" — taking two strings. It has to be, because app/fsm/layout.tsx keeps the interactive shell one file down specifically so these pages stay on the server and can export metadata, and a heading that reached for client state would undo the arrangement D-108 leaned on.
The paragraph each page passes it is that page's own metadata.description, now owned by a single const and used twice. The sentence Google already shows in the snippet is now also the first sentence of the page, which is where a crawler expects to find it corroborated rather than absent.
Footer anchor text is the only link every page carries
The footer product column said "CPQ Sandbox", "Mobile Tech App", "Live Dispatch Board" and "ROI Model" — the internal names again, on the block of links present on all 134 routes. It now says "CPQ software", "Field service management", "CPQ ROI calculator", "Dispatch board demo", "Field technician app" and "Client portal".
Two rows are new destinations rather than new labels. "Mobile Tech App" pointed at /platform/fms#mobile, a section of the marketing page, while /fsm/mobile — which *is* the technician app — had exactly one inbound link on the entire public site, and /fsm/portal had one as well; both came from /platform/fms, and the only other links to them are in FsmShell, which a crawler sees only after it has already reached /fsm. Both are "Discovered — currently not indexed", which is what a route with a single inbound link looks like from Google's side. The footer now links both directly, along with /platform/cpq and /platform/fms themselves, which the column previously reached only through a fragment. The #sandbox and #mobile sections remain reachable from their own pages.
This edit was made twice, and the first one shipped nothing. lib/constants.ts exported a FOOTER_COLUMNS that nothing imported: the footer that renders is components/layout/site-footer.tsx, which reads SITE_FOOTER_COLUMNS from config/site.ts. Both were arrays of { heading, links }, so editing the dead one type-checked, passed the link audit — which walks the config/site.ts structure — and deployed green. It was caught by reading the anchor text back off the production page rather than off the diff. The dead export has been deleted, not corrected, with a tombstone comment in its place; a duplicate that mirrors the live structure is indistinguishable from it at the moment of editing, which is the whole failure. Nothing incorrect was ever published: the old labels stayed on the site for the eleven minutes between the two deploys.
What was deliberately not done
The 107 URLs in "Discovered — currently not indexed" are almost entirely /engineering/decisions/*. It is tempting to read that as a quality signal and start trimming the sitemap. It is not one: "Crawled — currently not indexed" — the bucket that means Google fetched a page and declined it — stands at 0. Nothing on this site has been fetched and rejected. 107 URLs have never been fetched at all, on a sitemap first read twelve days ago. That is crawl budget on a young domain, and the answer to it is time and inbound links, not markup. Pulling the decision pages from the sitemap is the move D-108's reasoning already rejected.
No schema was added, because there was none left to add honestly. Organization and SoftwareApplication ship site-wide from app/layout.tsx, WebSite ships on the homepage, and FAQPage already ships on /faq, built from FAQ_ITEMS so that every question in the markup is answered in the server-rendered HTML. The offers node is an AggregateOffer with a lowPrice derived from PRICING_PLANS, because the pricing genuinely is published; there is still no aggregateRating, because there are still no third-party reviews to aggregate.
What would have to change for this to be wrong
If the titles start reading as keyword-stuffed to a human — if "CPQ software for trade contractors — parametric quoting that can't be wrong" is a sentence a buyer skims past where the shorter one made them stop — then the trade was bad and the category term belongs in the description alone. The measure is the click-through rate in Search Console's performance report on those six routes against their current baseline, not the ranking.
And the caveat worth writing down: these are on-page changes. They make the site legible to a search engine for the category it actually belongs to. They do not manufacture the domain authority that decides who ranks for "field service management software", a term contested by companies with a decade and a marketing budget on us.