2648 lines
177 KiB
Markdown
2648 lines
177 KiB
Markdown
# Migration Summary
|
||
|
||
## Status
|
||
|
||
A maintainable Astro migration and substantial fidelity-first pass are
|
||
implemented. The live public site was used as the authority for the shared
|
||
shell, English and Spanish homepages, service-page family, team page, library
|
||
indexes, and blog-post family.
|
||
|
||
## Migrated Content and Assets
|
||
|
||
- 46 English, 12 Spanish, and 7 Arabic library posts.
|
||
- 21 English, 9 Spanish, and 2 Arabic page records.
|
||
- One author record per language.
|
||
- 167 self-hosted images, 20 font files, and two PDF downloads.
|
||
- Current June and May 2026 English library articles are included.
|
||
|
||
HubSpot-generated wrappers, analytics, scripts, CSS, query-language duplicates,
|
||
AMP variants, pagination, and author archive variants are not carried into the
|
||
Astro implementation.
|
||
|
||
## Live-Source Fidelity Pass
|
||
|
||
Live pages inspected during the pass include:
|
||
|
||
- English and Spanish homepages
|
||
- ABA Therapy, Autism Evaluations, and Learner Social Club
|
||
- About, Team, Client Consultation, and Giveback & Donate
|
||
- English and Arabic Library indexes
|
||
- Representative current library articles
|
||
|
||
Implemented fidelity work includes:
|
||
|
||
- Rebuilt the live two-tier header, navigation hierarchy, language controls,
|
||
utility links, footer columns, and contact information.
|
||
- Rebuilt the complete English and Spanish homepages in their live section
|
||
order using one reusable Astro component and self-hosted source assets.
|
||
- Moved the English and Spanish homepage copy into section-oriented `home:`
|
||
frontmatter blocks so the page is easier to edit in Front Matter CMS.
|
||
- Rebuilt service pages around the live compact title banner and editorial
|
||
presentation, with current visible headings and working calls to action.
|
||
- Recovered and restored the live decorative hero imagery for all mapped
|
||
English and Spanish page routes plus every language's library index.
|
||
- Restored the consultation form section's injected background image.
|
||
- Added a dedicated live-derived team card grid rather than presenting the
|
||
extracted team content as a generic article.
|
||
- Rebuilt the contact page around the live two-column content/form section and
|
||
full-width Leaflet map while retaining local clickable obfuscated phone
|
||
links.
|
||
- Rebuilt the giveback page as four source-faithful full-width sections with
|
||
its original image/copy proportions, fundraiser color band, nonprofit logo,
|
||
emphasis, and external donation calls to action.
|
||
- Rebuilt library indexes and blog-post presentation around the live sidebar,
|
||
article list, byline, featured-image, and counter patterns.
|
||
- Converted FAQ-bearing posts to MDX and routed their accordions, the
|
||
standalone FAQ page, and the insurance FAQ through one reusable component.
|
||
Each accordion uses the same animated, single-open interaction and a
|
||
component-scoped caret color override; blog and insurance instances also
|
||
emit matching `FAQPage` JSON-LD.
|
||
- Restored 32 live-source blog blockquotes with their original emphasis,
|
||
links, fawn backgrounds, spacing, rounded presentation, and quote-mark SVG.
|
||
- Replaced generic oversized cards, rounded controls, and marketing heroes
|
||
with live-derived typography, palette, widths, spacing, and compact controls.
|
||
- Corrected material live-source discrepancies found during the pass,
|
||
including current homepage ESA copy, testimonial content, and ABA copy.
|
||
|
||
### Intentional visual deviations
|
||
|
||
- The homepage and `/insurance` carrier-logo rows intentionally share one
|
||
responsive layout. The first and last logos sit flush with the row edges,
|
||
and the Blue Cross Blue Shield mark is emphasized at 125% of the standard
|
||
desktop logo width, following its treatment on the live homepage rather
|
||
than preserving the live pages' differing row spacing.
|
||
- The Community 4 Autism logo on `/donate-autism-giveback` is horizontally
|
||
centered on mobile instead of retaining the live page's left alignment.
|
||
- The empty `<h6>` retained by the live `/schedule-consultation` page was
|
||
removed. It had no visible content and generated an empty heading ID in the
|
||
migrated Markdown, so omitting it improves heading semantics and fragment
|
||
integrity without removing page content.
|
||
|
||
## URLs and Redirects
|
||
|
||
Clean public URLs are preserved, including:
|
||
|
||
- `/aba-therapy`
|
||
- `/autism-evaluations`
|
||
- `/learner-social-club`
|
||
- `/client-consultation`
|
||
- `/library`
|
||
- `/library/post-slug`
|
||
- available `/es/...` and `/ar/library/...` routes
|
||
|
||
Phase 3A replaces the earlier 97-canonical sitemap with publication-policy
|
||
output: 92 local URLs in an indexing-enabled build and none in staging.
|
||
Nginx rewrites remain limited to the brief aliases `/aba`, `/autismevaluations`,
|
||
and `/learnersocialclub`.
|
||
|
||
## Forms
|
||
|
||
Visible consultation/contact-style pages render styled static HTML forms with
|
||
backend and spam-protection TODO comments. Submission is intentionally
|
||
disabled. Appointment and enrollment calls to action route to the static
|
||
consultation page rather than retaining the production Jotform backend.
|
||
|
||
The three English service pages also reproduce the live site's delayed,
|
||
right-edge inquiry drawers, including their page-specific enrollment copy,
|
||
shared field set, modal overlay, and responsive layout. These drawer forms are
|
||
static and their submit controls remain disabled until a production backend
|
||
and spam protection are selected; this is an intentional functional and visual
|
||
deviation from the live HubSpot form.
|
||
|
||
## External Dependencies
|
||
|
||
- The contact page map intentionally matches the live Leaflet/OpenStreetMap
|
||
implementation and loads Leaflet from `unpkg.com` plus map tiles from
|
||
`tile.openstreetmap.org`.
|
||
|
||
## Multilingual
|
||
|
||
- Spanish has the full live-derived homepage, translated service pages,
|
||
library index, and available translated posts.
|
||
- Arabic has RTL support, a clearly marked placeholder landing page, the live
|
||
library family, and available Arabic posts.
|
||
- Language-switcher choices are emitted only when the corresponding Astro
|
||
route exists, preventing dead translated-route links.
|
||
- Arabic pages use `lang="ar"` and `dir="rtl"`; English and Spanish use LTR.
|
||
- No large Arabic translations were invented.
|
||
|
||
## Likes and Views
|
||
|
||
The post counter uses `PUBLIC_AIA_API_BASE`, defaulting to
|
||
`https://api.azinstitute4autism.com`. Its contract was verified against the
|
||
current live-site script:
|
||
|
||
- `POST /stats/batch` for likes and views
|
||
- `POST /likes` to like
|
||
- `DELETE /likes/{slug}` to unlike
|
||
|
||
It preserves cookie-backed liked state and degrades gracefully if the API is
|
||
unavailable.
|
||
|
||
## SEO and Accessibility
|
||
|
||
- Canonicals, Open Graph tags, Twitter card tags, semantic titles, and global
|
||
organization JSON-LD are emitted by shared layouts.
|
||
- Organization JSON-LD intentionally omits raw `telephone` and `email` fields;
|
||
visible contact details use the Astro obfuscation component to avoid exposing
|
||
plain email and phone targets in rendered HTML.
|
||
- Library-index canonicals and current visible page H1s are explicitly set.
|
||
- Extracted image alt text is retained where available.
|
||
- Semantic landmarks, skip link, labeled forms, keyboard-operable navigation,
|
||
language/direction attributes, and responsive layouts are present.
|
||
- Sätteri heading attributes remain enabled. Markdown supports explicit
|
||
fragment IDs such as `{#accepted-insurance-heading}`; the installed MDX
|
||
parser requires HTML heading IDs instead. The earlier claim that MDX also
|
||
supports the shorthand was corrected during Phase 2 (see below).
|
||
- Sätteri directive parsing was disabled during Phase 2 after confirming that
|
||
there are no intentional consumers and that it silently removes literal
|
||
colon-containing text. No content or dependency versions were changed.
|
||
|
||
## Validation Results
|
||
|
||
- `npm audit --offline`: passed with zero known vulnerabilities under Node
|
||
`24.18.0`; `flake.nix` provides a compatible current Node release.
|
||
- `npm run audit:links`: passed with zero broken internal source links. The
|
||
audit now checks generated routes, root-relative references, relative
|
||
Markdown links, and public assets when rendered output is unavailable.
|
||
- `npm run audit:images`: passed with no missing mapped page banners, section
|
||
backgrounds, or blog featured images.
|
||
- `npm run audit:blog`: passed with no article-header content duplicated in
|
||
blog content and valid MDX FAQ components for 125 questions across 19 posts.
|
||
- `npm run generate:sitemap`: passed; generated 97 URLs.
|
||
- `npm run generate:redirects`: passed.
|
||
- All migration `.mjs` tools and the sandbox DNS helper pass `node --check`.
|
||
- The Astro compiler parsed all 49 `.astro` files successfully.
|
||
- `npm run build`: passed with zero Astro diagnostics and generated 97 static
|
||
pages.
|
||
- `npm run build:sandbox`: passed; generated 97 static pages.
|
||
- Live contact-page structure was inspected in browser at a 1280px desktop
|
||
viewport; local generated HTML was checked for the contact layout, Leaflet
|
||
assets, map container, and obfuscated clickable phone script. Local browser
|
||
rendering was blocked because the Playwright browser cannot reach shell
|
||
loopback servers and blocks `file:` URLs in this environment.
|
||
- Nix shell verification and `npm audit` retrieval were blocked by sandbox
|
||
proxy/cache network resets.
|
||
|
||
## Manual Review
|
||
|
||
- Perform full-page desktop and mobile visual comparisons for page-specific
|
||
layouts beyond the completed homepage, team, service, library, and article
|
||
families.
|
||
- Editorially review extracted long-form content for remaining extraction artifacts,
|
||
stale phone/email references, and heading hierarchy.
|
||
- Review all source alt text, keyboard behavior, screen-reader output, and
|
||
contrast with accessibility tooling.
|
||
- Have fluent reviewers approve Spanish content and Arabic RTL presentation.
|
||
- Select and connect a form backend with spam protection before launch.
|
||
- Validate like/view CORS, credentials, and production behavior after deployment.
|
||
|
||
## Phase 2: Markdown Rendering Repair — 2026-10-07 UTC
|
||
|
||
These are newly verified local rendering findings. The accepted Phase 1 audit
|
||
and route evidence remain unchanged. No production requests were made, no
|
||
source content was rewritten, and no dependencies were upgraded.
|
||
|
||
### Inspection and Cause
|
||
|
||
Before changing configuration, searched the Markdown/MDX corpus, documentation,
|
||
parser configuration, scripts, plugins, layouts, and rendering components for
|
||
container, leaf, and inline directives and their consumers. There are no
|
||
intentional directives or registered directive transformations. Documentation
|
||
examples in code fences, ordinary punctuation, URLs, times, ratios, frontmatter
|
||
fields, CSS selectors, and explicit heading IDs are not directive consumers.
|
||
|
||
For all 100 content files, stripped frontmatter and inspected the installed
|
||
Sätteri `markdownToMdast` / `mdxToMdast` output with the original
|
||
`headingAttributes: true, directive: true` features. This found 24 unintended
|
||
`textDirective` nodes in seven files, with zero container or leaf directives.
|
||
Sätteri treats colon suffixes such as `:1`, `:00`, and `:Plan` as inline
|
||
directives; without a transformation, the renderer drops those nodes. Astro's
|
||
MDX integration inherits the same processor features, so both formats were
|
||
affected. The original full build and the failing regression build confirmed
|
||
the resulting text loss.
|
||
|
||
Only `directive` was changed to `false`; `headingAttributes: true` is retained.
|
||
|
||
| Source under `src/content/` | Restored literal text | Unintended nodes |
|
||
| --- | --- | ---: |
|
||
| `pages/en/aba-therapy.mdx` | `1:1`, `1:2` in headings and prose | 4 |
|
||
| `pages/es/aba-therapy.md` | `1:1`, `1:2` in headings and prose | 4 |
|
||
| `blog/en/aba-school-readiness-arizona.mdx` | `1:1`, `1:10` in prose and tables | 4 |
|
||
| `blog/es/aba-school-readiness-arizona.mdx` | `1:1`, `1:10` in prose and tables | 3 |
|
||
| `pages/en/learner-social-club.mdx` | `4:00 PM – 6:00 PM`, twice | 4 |
|
||
| `pages/es/learner-social-club.mdx` | `4:00 p. m. – 6:00 p. m.`, twice | 4 |
|
||
| `pages/en/faqs.mdx` | `Opportunities:Plan breaks` | 1 |
|
||
|
||
### Regression and Generated-Output Verification
|
||
|
||
`npm run test:markdown` creates a temporary Astro project, loads the real
|
||
`astro.config.mjs`, and uses the existing dependencies and copied source
|
||
components/content. It builds representative `.md` and `.mdx` fixtures plus
|
||
all seven affected collection entries through `astro:content`'s `getEntry` and
|
||
`render`. The fixtures never enter the production route tree, and all temporary
|
||
files are removed after the run.
|
||
|
||
The 20 tests cover `1:1`, `1:2`, `1:10`, ordinary spaced and adjacent colon
|
||
punctuation, English/Spanish times, plain URLs and link destinations (including
|
||
port/query/fragment), inline/fenced code examples, MDX embedded markup, explicit
|
||
heading IDs and fragment links, and the affected real content. Before the
|
||
configuration change, 14 tests failed and six passed. Afterward, all 20 passed.
|
||
|
||
The full build still generates 97 pages. Comparing the before/after `<main>`
|
||
HTML on all 97 pages found changes only in the seven routes corresponding to
|
||
the table above. This comparison normalizes the existing random
|
||
`ContactObfuscation` IDs in span attributes and script variables; that component
|
||
was not changed. Generated `/aba-therapy` and `/es/aba-therapy` each now contain
|
||
both ratios in their headings and prose (two occurrences of each ratio).
|
||
|
||
All existing explicit IDs remain intact. Four automatically generated service
|
||
heading IDs now reflect the restored text:
|
||
|
||
| Route | Previous generated ID | Corrected generated ID |
|
||
| --- | --- | --- |
|
||
| `/aba-therapy` | `aba-therapy-1-program` | `aba-therapy-11-program` |
|
||
| `/aba-therapy` | `aba-therapy-1-academic-readiness-program` | `aba-therapy-12-academic-readiness-program` |
|
||
| `/es/aba-therapy` | `programa-de-terapia-aba-1` | `programa-de-terapia-aba-11` |
|
||
| `/es/aba-therapy` | `terapia-aba-1-programa-de-preparación-académica` | `terapia-aba-12-programa-de-preparación-académica` |
|
||
|
||
No source references to the old IDs were found. Compatibility with production
|
||
fragment links remains part of the later URL reconciliation; this repair does
|
||
not introduce redirects or edit service content.
|
||
|
||
The installed MDX parser rejects Markdown's `{#id}` shorthand with directive
|
||
parsing either enabled or disabled. This is a pre-existing limitation, not a
|
||
regression from the repair. No current content uses that shorthand. Tests
|
||
verify Markdown shorthand and MDX's supported `<h2 id="...">` syntax. README
|
||
guidance was corrected; a broader parser change is outside this phase.
|
||
|
||
### Validation
|
||
|
||
Run from `www/`:
|
||
|
||
```sh
|
||
npm run test:markdown
|
||
npm run build
|
||
npm run audit:links
|
||
npm run audit:blog
|
||
git diff --check
|
||
```
|
||
|
||
- Markdown regression tests: 20 passed, zero failures.
|
||
- Build: passed; 74 checked files, zero errors/warnings/hints, 97 static pages.
|
||
- Link audit: zero broken internal links.
|
||
- Blog audit: zero content audit failures.
|
||
- Diff whitespace check: passed.
|
||
- No changes to application content, dependencies, lockfile, Phase 1 evidence,
|
||
or `merge-plan.md`. No Phase 3 work was started.
|
||
|
||
## Phase 3A: Route Eligibility, Canonicals, and Indexing — 2026-10-07 UTC
|
||
|
||
This section records new implementation and verification. Earlier Phase 1
|
||
evidence and the Phase 2 checkpoint are preserved. No deployment, form
|
||
submission, backend activation, dependency change, content reconciliation,
|
||
hreflang, translation-alternate graph, article schema, or FAQ schema work was
|
||
performed.
|
||
|
||
### Publication Architecture
|
||
|
||
`src/utils/publication-policy.ts` is the shared, framework-independent
|
||
TypeScript policy. It derives local routes from collection/language/slug,
|
||
normalizes public paths, rejects route collisions (including drafts and utility
|
||
paths), validates canonicals, and decides route and sitemap eligibility.
|
||
`src/utils/publication.ts` adapts the Astro collections and reads the existing
|
||
`PUBLIC_ALLOW_INDEXING` switch. The canonical site origin comes from `site.json`,
|
||
also used by Astro configuration.
|
||
|
||
All content routes now pass through `src/pages/[...slug].astro`. The former
|
||
fixed home and Library routes could bypass `draft`; they now use the same
|
||
manifest as other pages. The existing Arabic home and three Library index
|
||
templates were moved to presentation components, retaining their visible
|
||
content. The English/Spanish home component receives its selected entry.
|
||
Shared layouts obtain canonical/indexing policy by the actual local route;
|
||
individual templates no longer invent or pass canonical strings.
|
||
|
||
The sitemap is an Astro endpoint generated alongside HTML. Its locations come
|
||
from eligible local route URLs, never canonical strings. The old public
|
||
sitemap copy was removed. `generate:sitemap` delegates to the Astro build
|
||
instead of maintaining a separate frontmatter-regex generator. Route discovery
|
||
and the source-link audit fallback reuse the shared publication policy; route
|
||
evidence now records eligibility, noindex, policy canonical, external-canonical
|
||
status, and production sitemap eligibility separately from rendered metadata.
|
||
|
||
The sole new frontmatter/schema field is `noindex`, a boolean defaulting to
|
||
false. Existing `draft` and `canonical` fields cover the remaining rules.
|
||
|
||
### Verified Exceptions and Read-Only Production Evidence
|
||
|
||
Six successful GET requests were made between **02:42:02 and 02:42:08 UTC**:
|
||
`robots.txt` first, then the five routes below. Requests were sequential, at
|
||
least one second apart, with redirects not followed. Robots allowed these
|
||
paths. No publisher pages, forms, or production APIs were requested. The web
|
||
tool could not retrieve robots.txt; the direct GET succeeded. All five route
|
||
observations agree with the accepted saved production evidence; these are
|
||
new checks, not silent revisions to historical findings.
|
||
|
||
| Route | Fresh HTTP / robots evidence | Implemented exception | Production sitemap |
|
||
| --- | --- | --- | --- |
|
||
| `/ar` | 404 at 02:42:08 | Existing placeholder marked `draft: true`; no HTML route | Excluded |
|
||
| `/schedule-consultation` | 200 / `noindex` at 02:42:04 | `noindex: true`; accessible, self-canonical | Excluded |
|
||
| `/employee-portal` | 200 / `noindex` at 02:42:05 | `noindex: true`; accessible, self-canonical | Excluded |
|
||
| `/library/community-highlight-meet-rula-diab` | 200 / `noindex` at 02:42:06 | `noindex: true`; external canonical retained | Excluded |
|
||
| `/library/new-aia-scottsdale-office` | 200 / `noindex` at 02:42:07 | `noindex: true`; external canonical retained | Excluded |
|
||
|
||
The exact verified external canonical targets are:
|
||
|
||
- [VoyagePhoenix original](https://voyagephoenix.com/interview/community-highlights-meet-rula-diab-of-arizona-institute-for-autism/)
|
||
- [Scottsdale.org original](https://www.scottsdale.org/airpark/features/integrity-empowerment-and-excellence-arizona-institute-for-autism-expands-to-new-office/article_79c31a18-2f35-11ee-9459-6f29f5a08420.html)
|
||
|
||
Only five content files changed, all in frontmatter: the Arabic home draft
|
||
flag, four noindex flags, and the two external canonical values. Portal access
|
||
and replacement behavior remain unchanged and deferred to human decision.
|
||
|
||
### Before / After and Output Verification
|
||
|
||
| Behavior | Before Phase 3A | After Phase 3A |
|
||
| --- | --- | --- |
|
||
| Route publication | Collection routes filtered drafts; fixed indexes bypassed them | Every content route uses the same eligibility manifest |
|
||
| Generated HTML | 97 pages, including `/ar` placeholder | 96 pages; only `/ar` removed |
|
||
| Canonical handling | Optional unchecked values passed by templates; syndicated posts self-canonicalized | Exactly one normalized self canonical, or the verified external exception; missing ordinary values derive from the route |
|
||
| Indexing-enabled robots | All pages defaulted to indexable | 92 `index,follow`; four verified `noindex,follow` exceptions |
|
||
| Staging robots | Global `noindex,nofollow` | Global protection retained on all 96 pages; no page override |
|
||
| Sitemap | Static list of 97 frontmatter canonicals | 92 eligible local URLs when indexing is enabled; empty in staging |
|
||
| Robots sitemap advertisement | Environment dependent | Still advertised only in the indexing-enabled build |
|
||
|
||
Published noindex pages remain accessible. An external canonical independently
|
||
excludes a page from the sitemap; it does not automatically invent a noindex
|
||
directive. The two real syndicated articles explicitly retain their verified
|
||
noindex status. Invalid/relative/unsafe canonicals, local targets that disagree
|
||
with the route or public origin, duplicate published canonical targets, and
|
||
route collisions fail validation. Duplicate frontmatter keys also fail parsing.
|
||
|
||
The language menu now uses eligible routes without a hardcoded `/ar` entry.
|
||
The Arabic header logo falls back to the existing English homepage while its
|
||
localized homepage is unpublished. No hreflang or new translation relationships
|
||
were introduced. Main content text, titles, and H1s are unchanged on all 96
|
||
retained routes. There are no stylesheet or asset changes.
|
||
|
||
The indexing-enabled local artifact was checked at **02:54:56 UTC**: all 96
|
||
heads matched their manifest canonicals/robots; 92 local sitemap URLs; no `/ar`.
|
||
The final ordinary build restores staging output with 96 noindex pages and
|
||
zero sitemap locations. No environment files or deployment configuration changed.
|
||
|
||
### Regression Coverage and Reproduction
|
||
|
||
`npm run test:publication` passes **19 tests** covering normal publication,
|
||
draft exclusion, accessible noindex pages, external canonicals independently
|
||
of noindex, normalized/missing/malformed/duplicate canonicals, cross-collection
|
||
and cross-locale collisions, reserved routes, staging protection, and all five
|
||
verified exceptions. Generated-head checks reject absent, duplicate, and invalid
|
||
canonical tags. It builds the actual application in temporary directories in
|
||
both environment modes, then additionally marks a home and Library index as
|
||
drafts and confirms their routes disappear. The tests never change real source,
|
||
environment configuration, or `dist`.
|
||
|
||
Validation from `www/`, in the requested order (with evidence refresh steps):
|
||
|
||
```sh
|
||
npm run test:publication
|
||
npm run build
|
||
PUBLIC_ALLOW_INDEXING=true npm run build
|
||
npm run audit:routes -- --offline
|
||
npm run audit:routes -- --check
|
||
npm run audit:links
|
||
npm run build
|
||
npm run audit:routes -- --offline
|
||
npm run audit:routes -- --check
|
||
git diff --check
|
||
```
|
||
|
||
All required commands passed. Each build checked 71 files with zero errors,
|
||
warnings, or hints, and generated 96 HTML pages. The link audit found zero
|
||
broken internal links. Existing regression suites also passed: 20 Markdown
|
||
tests and nine route-audit tests. Dependencies and the lockfile are unchanged.
|
||
The source-only link fallback also passed in an isolated directory with zero
|
||
broken links. The `generate:sitemap` compatibility command was verified using
|
||
Astro's public build API, followed by another normal staging build.
|
||
|
||
The final durable local reconciliation is
|
||
[`route-reconciliation-2026-10-07-offline-04-11-25-151Z.json`](route-reconciliation-2026-10-07-offline-04-11-25-151Z.json).
|
||
It reuses the earlier 70 production request records with their original
|
||
observation dates; neither offline reconciliation made new production requests.
|
||
Only the final staging reconciliation is retained in the repository; the
|
||
intermediate indexing reconciliation was moved to temporary storage after its
|
||
checks. The six targeted requests described above are separate fresh evidence.
|
||
|
||
The normalized discovery inventory remains 129 routes, with 102 URLs in the
|
||
saved production sitemap. Local generated routes decrease from 97 to 96;
|
||
sitemap/local overlap stays 92, and the ten sitemap-listed live-only routes
|
||
remain outstanding. `/ar` remains visible in the inventory as draft,
|
||
ineligible, not generated, and verified absent on production. Earlier audit
|
||
files retain their historical facts.
|
||
|
||
No new human publication-policy decision is needed for Phase 3A. Human gates
|
||
for portal access, forms/backends, analytics/consent, landing-page ownership,
|
||
and conflicting service facts remain deferred. Phase 3B was not started.
|
||
|
||
## Phase 3B: Explicit Translation Relationships and Hreflang — 2026-10-07 UTC
|
||
|
||
This section records new work after the accepted Phase 3A structural review.
|
||
Earlier audit findings and implementation history above remain historical.
|
||
Starting branch: `faithful-astro-migration`; HEAD: `1e1aafa`. The only commit
|
||
after Phase 3A (`cd097d0`) added the conversation transcript. The Phase 1 and
|
||
Phase 2 checkpoints remain `60c534d` and `ea2f1ea`. This work is not committed.
|
||
|
||
### Inspection and Policy
|
||
|
||
The existing manifest owns every generated content route and already supplies
|
||
eligibility, normalized local URL, canonical, noindex, external-canonical and
|
||
sitemap eligibility. Inspection found 32 page records, 65 blog records and
|
||
three author records, all declaring `translationKey`. No hreflang was emitted.
|
||
The language switcher was the only equivalent-route guesser: it removed a
|
||
language prefix and tried the same URL suffix in all languages. The Header's
|
||
locale-home fallback is navigation, not a translation relationship, and remains
|
||
unchanged.
|
||
|
||
`createPublicationManifest` in `src/utils/publication-policy.ts` now groups
|
||
explicit keys within each collection. It attaches one validated `translations`
|
||
array to every eligible member of a multilingual set. Each reference contains
|
||
the declared language and the target's actual manifest route and absolute URL.
|
||
It never derives an equivalent from a slug, filename or URL suffix.
|
||
|
||
Participation reuses `sitemapEligible`: a generated/published entry that is
|
||
indexable and self-canonical under the production policy. At least two eligible
|
||
languages are required. All members, including drafts, are checked for duplicate
|
||
language declarations before filtering; two entries for the same collection,
|
||
key and language fail validation. The graph validator rejects dangling targets,
|
||
wrong collection/key/language/URL, ineligible endpoints, duplicate languages,
|
||
missing self references and nonreciprocity. All members share the same complete,
|
||
ordered set, so reciprocity is generated rather than manually maintained.
|
||
|
||
**Grouping versus missing references:** `translationKey` is an optional grouping
|
||
label, not a pointer or a list of required locales. A singleton remains valid
|
||
and emits no alternates; it does not assert that a Spanish/Arabic record exists.
|
||
An absent referenced graph node fails policy validation; an absent referenced
|
||
HTML file fails rendered-output validation. A typo that creates a new singleton
|
||
or deletion of the last counterpart cannot be distinguished from intentionally
|
||
standalone content by this schema. No new required-target field or guessed
|
||
language requirement was introduced.
|
||
|
||
The existing optional `translationKey` schema now rejects empty and
|
||
whitespace-padded values in pages, blog and authors. There are no new frontmatter
|
||
fields and **no content/frontmatter edits**. Placeholders must remain drafts;
|
||
the only marked content placeholder is `/ar`, already `draft: true`.
|
||
|
||
### Current Explicit Sets
|
||
|
||
The existing declarations produce **24 sets / 53 participating routes**:
|
||
nine page sets (19 routes) and 15 blog sets (34 routes). English contributes
|
||
24 members, Spanish 21, Arabic eight. There are 19 two-language sets and five
|
||
three-language sets. The following inventory lists actual local routes, not
|
||
inferred URLs. A dash means there is no eligible declared counterpart.
|
||
|
||
| Collection / key | English | Spanish | Arabic |
|
||
| --- | --- | --- | --- |
|
||
| pages / index | `/` | `/es` | — |
|
||
| pages / library | `/library` | `/es/library` | `/ar/library` |
|
||
| pages / aba-therapy | `/aba-therapy` | `/es/aba-therapy` | — |
|
||
| pages / aba-therapy-intake-process | `/aba-therapy-intake-process` | `/es/aba-therapy-intake-process` | — |
|
||
| pages / autism-evaluations | `/autism-evaluations` | `/es/autism-evaluations` | — |
|
||
| pages / client-consultation | `/client-consultation` | `/es/client-consultation` | — |
|
||
| pages / contact | `/contact` | `/es/contact` | — |
|
||
| pages / learner-social-club | `/learner-social-club` | `/es/learner-social-club` | — |
|
||
| pages / services | `/services` | `/es/services` | — |
|
||
| blog / aba-school-readiness-arizona | `/library/aba-school-readiness-arizona` | `/es/library/aba-school-readiness-arizona` | — |
|
||
| blog / aba-school-readiness-guide | `/library/aba-school-readiness-guide` | — | `/ar/library/aba-school-readiness-guide` |
|
||
| blog / autism-evaluation-diagnosis-arizona-parent-guide | `/library/autism-evaluation-diagnosis-arizona-parent-guide` | `/es/library/autism-evaluation-diagnosis-arizona-parent-guide` | — |
|
||
| blog / autism-evaluation-what-to-expect | `/library/autism-evaluation-what-to-expect` | `/es/library/autism-evaluation-what-to-expect` | — |
|
||
| blog / autism-family-self-care-tips | `/library/autism-family-self-care-tips` | `/es/library/autism-family-self-care-tips` | — |
|
||
| blog / autism-self-advocacy-skills-aba | `/library/autism-self-advocacy-skills-aba` | `/es/library/autism-self-advocacy-skills-aba` | `/ar/library/autism-self-advocacy-skills-aba` |
|
||
| blog / behavior-management-functions-guide | `/library/behavior-management-functions-guide` | — | `/ar/library/behavior-management-functions-guide` |
|
||
| blog / emotional-regulation-aba | `/library/emotional-regulation-aba` | `/es/library/emotional-regulation-aba` | — |
|
||
| blog / enhancing-generalization-skills | `/library/enhancing-generalization-skills` | `/es/library/enhancing-generalization-skills` | — |
|
||
| blog / executive-functioning-skills-autism | `/library/executive-functioning-skills-autism` | `/es/library/executive-functioning-skills-autism` | `/ar/library/executive-functioning-skills-autism` |
|
||
| blog / first-then-cards-autism-transitions | `/library/first-then-cards-autism-transitions` | `/es/library/first-then-cards-autism-transitions` | `/ar/library/first-then-cards-autism-transitions` |
|
||
| blog / parents-guide-to-autism-and-aba | `/library/parents-guide-to-autism-and-aba` | `/es/library/parents-guide-to-autism-and-aba` | — |
|
||
| blog / positive-reinforcement-techniques | `/library/positive-reinforcement-techniques` | `/es/library/positive-reinforcement-techniques` | `/ar/library/positive-reinforcement-techniques` |
|
||
| blog / proactive-reactive-aba-strategies-guide | `/library/proactive-reactive-aba-strategies-guide` | — | `/ar/library/proactive-reactive-aba-strategies-guide` |
|
||
| blog / social-pragmatic-communication-autism | `/library/social-pragmatic-communication-autism` | `/es/library/social-pragmatic-communication-autism` | — |
|
||
|
||
Excluded: `/ar` is draft and uses `home`, not the published home set's `index`
|
||
key; its key was not changed. `/schedule-consultation`, `/employee-portal`,
|
||
`/library/community-highlight-meet-rula-diab`, and
|
||
`/library/new-aia-scottsdale-office` remain noindex; the latter two also retain
|
||
external canonicals. None can be a source or target. Three `authors:rula-diab`
|
||
records share a key but have no generated author routes and do not enter the
|
||
graph. The other 39 indexable routes have no eligible translated counterpart.
|
||
Live-only Spanish privacy, author/archive/search routes and missing languages
|
||
are not manufactured. There are no additional current URL-matched published
|
||
pairs lacking explicit keys; different-slug and unkeyed same-slug fixtures test
|
||
that future content will not be guessed.
|
||
|
||
### SEO, Navigation and Default Language
|
||
|
||
`Seo.astro` calls the shared `hreflangLinksFor` helper. An indexing-enabled build
|
||
emits absolute alternate URLs, including the page itself, on each set member.
|
||
English is the project's established default; `x-default` points to that set's
|
||
eligible English member, never an unrelated homepage. A set without eligible
|
||
English omits `x-default` (covered with Spanish/Arabic fixtures and excluded
|
||
English fixtures). All 24 current sets have an eligible English member.
|
||
|
||
This follows [Google's localized-page guidance](https://developers.google.com/search/docs/specialty/international/localized-versions)
|
||
on fully qualified, reciprocal, self-referencing alternates and an appropriate
|
||
default. Staging emits no hreflang; its global `noindex,nofollow` and empty
|
||
sitemap remain intact. The graph still supplies local language navigation.
|
||
|
||
`LanguageSwitcher.astro` uses those same manifest equivalents and the entry's
|
||
declared language for its active label. It constructs no counterpart URLs.
|
||
Labels, SVG and CSS are unchanged. Without a translation set, it retains the
|
||
current-language label but emits no empty menu, focusable trigger or listbox
|
||
promise. Existing translated sets keep self and equivalent links. Header and
|
||
route/template dispatch code are unchanged.
|
||
|
||
### Fresh Production Observations
|
||
|
||
Six read-only GETs on **2026-10-07 23:00:32–23:00:38 UTC**, at least one second
|
||
apart, checked robots first and then these five pages. Robots permitted the
|
||
paths; all six responses were HTTP 200, with no redirects followed. No forms,
|
||
APIs, broad crawl or production writes were used; no production HTML is added
|
||
to the repository. These checks supplement, rather than rewrite, earlier audit
|
||
evidence.
|
||
|
||
| Observed page | Check time UTC | Declared production alternates |
|
||
| --- | --- | --- |
|
||
| `/` | 23:00:33 | en `/`, es `/es/`, x-default `/` |
|
||
| `/library` | 23:00:35 | en-us `/library`, es `/es/library`, ar `/ar/library` |
|
||
| `/library/autism-self-advocacy-skills-aba` | 23:00:36 | en-us, es, ar, x-default English |
|
||
| `/es/library/autism-self-advocacy-skills-aba` | 23:00:37 | en-us, es, ar, x-default English |
|
||
| `/ar/library/autism-self-advocacy-skills-aba` | 23:00:38 | en-us, es, ar, x-default English |
|
||
|
||
The article's three observations reference the same three full article paths
|
||
listed in the set inventory. The homepage and article use English defaults.
|
||
Production's Library index has no x-default; the local policy adds its real
|
||
English index as the default, consistent with the approved rule. Library
|
||
production labels English `en-us`; local output uses the existing content
|
||
language `en`, without inventing regional variants. Relationships are based on
|
||
explicit existing content declarations, supported by these targeted checks;
|
||
this is not a new full content reconciliation or linguistic-fluency approval.
|
||
|
||
### Validation and Structural Review
|
||
|
||
`npm run test:publication`: **33 passed**, including the original 19 Phase 3A
|
||
tests and 14 translation tests. Coverage includes different-slug equivalence,
|
||
unrelated matching slugs, collection boundaries, all publication exclusions,
|
||
malformed/duplicate keys, dangling graph/generated references, reciprocity,
|
||
self references, default eligibility and identical switcher/SEO membership.
|
||
Isolated real-Astro builds exercise staging, indexing and draft home/Library
|
||
indexes without changing the real content or deploying anything.
|
||
|
||
The requested validation sequence passed (offline refreshes keep source
|
||
fingerprints current without making discovery requests):
|
||
|
||
```sh
|
||
cd www
|
||
npm run test:publication
|
||
npm run build
|
||
PUBLIC_ALLOW_INDEXING=true npm run build
|
||
npm run audit:routes -- --offline
|
||
npm run audit:routes -- --check
|
||
npm run audit:links
|
||
npm run build
|
||
npm run audit:routes -- --offline
|
||
npm run audit:routes -- --check
|
||
git diff --check
|
||
```
|
||
|
||
All three regular build invocations checked 71 files with zero errors, warnings
|
||
or hints, and generated 96 HTML routes. The link audit found zero broken links.
|
||
At 23:02:40 UTC, the indexing artifact had 92 sitemap entries, 92 indexable
|
||
pages and four noindex exceptions, with 174 hreflang links on 53 routes across
|
||
24 sets. Canonicals matched the pre-change artifact on every retained route.
|
||
At 23:03:49 UTC, the final staging artifact had 96 `noindex,nofollow` pages,
|
||
zero sitemap entries and zero hreflang links. Every language menu matched the
|
||
graph. Route set, titles, canonical URLs, language/direction and main content
|
||
matched the pre-change artifact; the main-content comparison excludes script
|
||
nodes and normalizes whitespace and existing random contact-obfuscation IDs.
|
||
|
||
The final durable route evidence is
|
||
[`route-reconciliation-2026-10-07-offline-23-03-24-581Z.json`](route-reconciliation-2026-10-07-offline-23-03-24-581Z.json).
|
||
It preserves the original 70 production request records and observation times.
|
||
The discovery inventory remains 129 routes, production sitemap inventory 102,
|
||
local generated 96, local/sitemap overlap 92 and live-sitemap local omissions
|
||
10. Those production counts are historical discovery evidence, not the local
|
||
92-entry production-policy sitemap. The intermediate indexing reconciliation
|
||
is retained only in temporary storage; both modes are reproducible above.
|
||
|
||
The diff is confined to the shared publication policy, translation-key schema
|
||
validation, switcher, SEO component, existing publication tests, README, this
|
||
report and the final dated route reconciliation. No content/frontmatter, route
|
||
templates, styles, dependencies, environment files or deployment settings were
|
||
changed. No Phase 3A blocker or accounting defect was found. The original
|
||
`merge-plan.md` remains untracked with SHA-256
|
||
`015db80cdbaf7d68799265d2070db760155c342b432ce6795f17ebc2218c641c`.
|
||
|
||
No new human publication-policy decision is required. Existing decisions about
|
||
employee access, campaign ownership, forms, analytics/consent and conflicting
|
||
eligibility claims remain deferred. Substantive future translations require
|
||
human language review. Phase 4A, article/FAQ schema, content reconciliation,
|
||
visual fidelity and deployment work were not started. Stop for review before
|
||
any Phase 3B checkpoint commit.
|
||
|
||
## Phase 4A — Display Headings and Social Metadata (2026-10-08)
|
||
|
||
This section records new implementation and observations after checkpoint
|
||
`32112edbde7f90d01becf5d420ff189bf8b7e6ec` on `faithful-astro-migration`.
|
||
Earlier audit and phase sections remain historical evidence. Phase 4B,
|
||
substantive content reconciliation, Library features and deployment are outside
|
||
this milestone. No changes have been staged or committed; stop for acceptance
|
||
of the implementation and structural review.
|
||
|
||
### Inspection and Architecture
|
||
|
||
Before changes, articles used `title` for both document title and H1. Regular
|
||
pages used `serviceTitles`, `pageTitles`, then the part of `title` preceding
|
||
`|`. Home and Library components owned their headings. `Seo.astro` already
|
||
handled OG metadata and Twitter title/description/card, but lacked
|
||
`twitter:image`; it emitted content language codes as `og:locale`. Publication,
|
||
robots, canonical, sitemap, hreflang and LanguageSwitcher membership were
|
||
already governed by the Phase 3A/3B manifest and remain so.
|
||
|
||
The shared pages/blog Zod schema now accepts optional `displayH1`. It must be a
|
||
string containing non-whitespace text. Omission preserves existing behavior;
|
||
empty, whitespace-only and non-string explicit values fail validation. Both
|
||
Front Matter CMS content types expose the field. No author or social-specific
|
||
schema fields were added.
|
||
|
||
- BlogPostLayout selects `displayH1 ?? title` for its existing H1 only.
|
||
- PageLayout selects `displayH1 ?? bannerTitle` only at PageHero. All existing
|
||
heading maps and fallbacks remain intact. Form and contact heading props
|
||
continue to receive the original banner title, avoiding collateral changes.
|
||
- HomePage passes the optional override to HomeHero. Without one, existing
|
||
source heading HTML, including line breaks, is preserved. An override is
|
||
escaped plain text and replaces the single H1, never adds another one.
|
||
- BlogIndexLayout reads the current manifest entry for an explicit H1 override.
|
||
Its existing title prop continues to control the document/social titles and
|
||
default H1. Existing locale-specific Library template titles are unchanged.
|
||
|
||
Cards, navigation labels, related-post text, article bodies, styles and client
|
||
code are unchanged. No content routes, policy fields or translation pairs were
|
||
added. The unpublished Arabic homepage remains unpublished.
|
||
|
||
### Newly Verified Heading Evidence
|
||
|
||
Two batches of read-only production requests on 2026-10-08 respected robots
|
||
and spaced page requests by at least one second. Nine GETs total comprised two
|
||
robots checks and seven article checks across four unique article URLs. All
|
||
returned HTTP 200; no redirects were followed, forms submitted, APIs called or
|
||
production assets downloaded. Three article checks were repeated with the
|
||
document-title selector restricted to `head title`, excluding inline SVG title
|
||
elements from the initial extraction. Only the corrected document titles below
|
||
are used as heading evidence. No production HTML captures are committed.
|
||
|
||
| Production URL | Observation UTC | Document title | Visible H1 | Local action |
|
||
| --- | --- | --- | --- | --- |
|
||
| [English self-advocacy](https://www.azinstitute4autism.com/library/autism-self-advocacy-skills-aba) | 2026-10-08 21:11:28 | Unlock Independence for Children with Autism Through ABA Self‑Advocacy | Guide to Teaching Self‑Advocacy in ABA | Add this `displayH1` only to `src/content/blog/en/autism-self-advocacy-skills-aba.md` |
|
||
| [Spanish self-advocacy](https://www.azinstitute4autism.com/es/library/autism-self-advocacy-skills-aba) | 2026-10-08 21:11:29 | Desbloqueando la independencia para niños con autismo a través de la autodefensa ABA | Guía para enseñar la autodefensa en el ABA | Add this `displayH1` only to `src/content/blog/es/autism-self-advocacy-skills-aba.md` |
|
||
| [Arabic self-advocacy](https://www.azinstitute4autism.com/ar/library/autism-self-advocacy-skills-aba) | 2026-10-08 21:11:30 | دليل تعليم مهارات الدفاع عن النفس في ABA | دليل تعليم مهارات الدفاع عن النفس في ABA | No change; existing title-to-H1 fallback is correct |
|
||
|
||
The English nonbreaking hyphen and Spanish heading are copied from the current
|
||
source, not newly translated. These are the only two content-record edits;
|
||
each adds one frontmatter line. Titles, descriptions, images, bodies and
|
||
translation declarations are untouched. This is not a linguistic review of
|
||
the translations or a broader certification of content currency.
|
||
|
||
A separate targeted check of
|
||
[`/library/aba-school-readiness-arizona`](https://www.azinstitute4autism.com/library/aba-school-readiness-arizona)
|
||
at **2026-10-08 21:07:17 UTC** found current OG title
|
||
“ABA School Readiness in Arizona: A Parent Guide” and H1
|
||
“ABA School Readiness for Autistic Children in Arizona.” The existing local
|
||
title is “ABA School Readiness in Arizona | AIA Preparatory Academy (Ages 2–6).”
|
||
The current live description also discusses classroom participation and
|
||
individualized ABA. This is fresh evidence of broader drift requiring later
|
||
content reconciliation; that record is intentionally unchanged in Phase 4A.
|
||
|
||
### Social Metadata and Locale
|
||
|
||
`Seo.astro` uses a small `socialImageUrl` helper to resolve existing image paths
|
||
against the configured public origin in `src/data/site.json`. It never uses a
|
||
preview request host or an article's external canonical as the asset base.
|
||
Absolute HTTP(S) image URLs are supported; blank selections produce no image,
|
||
and invalid URLs, non-HTTP(S) schemes or embedded credentials fail validation.
|
||
|
||
Image pages now emit matching absolute `og:image` and `twitter:image` once
|
||
each, retaining `summary_large_image`. Non-image pages emit neither image nor
|
||
image-alt metadata and retain `summary`. Existing image selection is unchanged:
|
||
article featured images and regular-page featured images/banner fallbacks are
|
||
preserved. No homepage image is invented merely because a hero image exists.
|
||
The real artifact has **90 image cards and six summary cards** in each mode.
|
||
Every emitted local social image resolves to an existing public asset.
|
||
|
||
BaseLayout forwards existing `alt` only when the selected image is the entry's
|
||
`featuredImage`. Seo emits both `og:image:alt` and `twitter:image:alt` only for a
|
||
nonblank description with a selected image. An unrelated banner fallback never
|
||
inherits that description. The current local pages/blog corpus has no
|
||
nonempty featured-image `alt` values, so no real image-alt tags are fabricated;
|
||
isolated fixtures prove the supported path in all three languages. Production
|
||
self-advocacy pages do have social alt descriptions. Importing those into local
|
||
content and reviewing visible image descriptions remain later content work.
|
||
|
||
`og:title`, `og:description`, `og:url`, `og:type`, Twitter title/description and
|
||
card selection otherwise retain their behavior. Articles remain `article` and
|
||
other pages `website`. No structured-data types were added.
|
||
|
||
The [Open Graph protocol](https://ogp.me/) defines the optional `og:locale` as
|
||
`language_TERRITORY`. Existing generic `en`, `es` and `ar` values were removed;
|
||
neither the frontmatter nor inspected production articles establish regional
|
||
assignments, and those production articles emit no `og:locale`. Omission avoids
|
||
inventing regions. Open Graph documents `en_US` as its default when omitted,
|
||
so intentional Spanish/Arabic social-region targeting remains an unresolved
|
||
human localization choice, not a claim that omission supplies it. HTML `lang`,
|
||
RTL/LTR direction, hreflang and `x-default` are unchanged.
|
||
|
||
### Validation
|
||
|
||
`npm run test:seo`: **12 passed**. Tests use the actual content schema, layouts,
|
||
SEO component and Astro configuration in temporary copies, covering:
|
||
|
||
- Original article H1 fallback and explicit override in en/es/ar; independent
|
||
document/social/card titles; both production-supported records.
|
||
- Existing service, regular-page and derived headings; single H1; homepage
|
||
inline heading markup and explicit home/Library overrides.
|
||
- Absolute root/path-relative and external image URLs, invalid/blank URLs,
|
||
preview-host isolation, paired image metadata, existing alt and absent alt,
|
||
no-image fallback, article type and language/direction.
|
||
- Shared publication-policy results on every generated fixture route in
|
||
staging/indexing: canonical, robots, sitemap, hreflang and switcher targets,
|
||
including all noindex/external-canonical exceptions and absent `/ar`.
|
||
- Actual failed content builds for `displayH1` values `""`, spaces, newline/tab
|
||
and a number. Markdown records and an MDX service record exercise rendering.
|
||
|
||
The first test run exposed a fixture path using `.md` for the existing MDX ABA
|
||
service record; that test-only path was corrected before continuing. There
|
||
were no remaining test failures. `npm run test:publication`: **33 passed**,
|
||
unchanged from Phase 3B.
|
||
|
||
Completed commands, from `www/`:
|
||
|
||
```sh
|
||
npm run test:seo
|
||
npm run test:publication
|
||
npm run build
|
||
PUBLIC_ALLOW_INDEXING=true npm run build
|
||
npm run audit:routes -- --offline
|
||
npm run audit:routes -- --check
|
||
npm run audit:links
|
||
npm run audit:blog
|
||
npm run audit:images
|
||
npm run build
|
||
npm run audit:routes -- --offline
|
||
npm run audit:routes -- --check
|
||
git diff --check
|
||
```
|
||
|
||
Each normal/indexing build checked 73 files with **zero errors, warnings or
|
||
hints**, and generated **96 HTML routes**: 67 English, 21 Spanish, eight Arabic.
|
||
Link audit: **zero broken internal links**. Blog audit: **zero failures**.
|
||
Image audit: **zero missing mapped page images**; the generated social-image
|
||
check additionally verified all selected local image files. These are local
|
||
artifact checks, not verification of every external URL or social-platform
|
||
preview/cache behavior.
|
||
|
||
| Artifact | Checked UTC, 2026-10-08 | HTML routes | Sitemap URLs | Robots | Hreflang |
|
||
| --- | --- | ---: | ---: | --- | --- |
|
||
| Indexing-enabled local build | 21:16:30 | 96 | 92 | 92 `index,follow`; four `noindex,follow` | 174 links on 53 routes, same 24 explicit sets |
|
||
| Final normal staging build | 21:17:16 | 96 | 0 | All 96 `noindex,nofollow` | Zero links |
|
||
|
||
All 96 canonicals match the pre-change artifact and the shared policy. The
|
||
four exceptions remain `/schedule-consultation`, `/employee-portal`,
|
||
`/library/community-highlight-meet-rula-diab` and
|
||
`/library/new-aia-scottsdale-office`. Neither they nor unpublished `/ar` enter
|
||
the alternate graph or production-policy sitemap. Social URLs do not affect
|
||
route eligibility or canonical selection.
|
||
|
||
An all-route semantic comparison against the pre-change staging artifact found
|
||
exactly the two supported H1 changes. Remaining body markup, navigation and
|
||
scripts match after normalizing whitespace and existing random contact IDs;
|
||
H1 text is compared separately. Remaining head markup also matches after
|
||
excluding the intended social-tag differences and mode-dependent robots and
|
||
hreflang. No title, description, existing OG image, URL, direction, client
|
||
behavior or JSON-LD changes were introduced.
|
||
|
||
The final durable reconciliation is
|
||
[`route-reconciliation-2026-10-08-offline.json`](route-reconciliation-2026-10-08-offline.json).
|
||
It refreshes the application fingerprint and final staging output using the
|
||
same 70 saved production requests and their original observation dates. No
|
||
route-discovery network requests were made. The new targeted heading checks
|
||
above supplement that historical discovery evidence rather than overwrite it.
|
||
Counts remain 129 discovered routes, 102 historical production sitemap routes,
|
||
96 local routes, 92 overlapping routes and 10 production-sitemap routes absent
|
||
locally. The historical 102 is distinct from the local policy's 92. The
|
||
intermediate indexing reconciliation was moved to temporary storage before
|
||
the final staging reconciliation; prior committed evidence files are intact.
|
||
|
||
### Read-only Structural Review and Scope
|
||
|
||
The complete Phase 4A change set contains 17 files:
|
||
|
||
| Classification | Files relative to `www/` | Reason |
|
||
| --- | --- | --- |
|
||
| Schema/editor configuration | `src/content.config.ts`, `frontmatter.json` | Optional validated heading field on pages/blog and CMS exposure |
|
||
| Presentation | `src/layouts/BlogPostLayout.astro`, `src/layouts/PageLayout.astro`, `src/layouts/BlogIndexLayout.astro`, `src/components/pages/HomePage.astro`, `src/components/home/HomeHero.astro` | Explicit single-H1 override, preserving each template's default |
|
||
| SEO | `src/components/Seo.astro`, `src/layouts/BaseLayout.astro`, **new** `src/utils/seo.ts` | Paired absolute social images, conditional existing alt, removal of unsupported generic OG locales |
|
||
| Tests | **new** `tools/seo.test.mjs`, `package.json` | Actual Astro/schema regression coverage and `test:seo`; no dependency changes |
|
||
| Content metadata | `src/content/blog/en/autism-self-advocacy-skills-aba.md`, `src/content/blog/es/autism-self-advocacy-skills-aba.md` | One source-supported frontmatter line per record |
|
||
| Documentation/evidence | `README.md`, this report, **new** `reports/route-reconciliation-2026-10-08-offline.json` | Editing rules, dated evidence/results, current offline fingerprint |
|
||
|
||
No changes to publication-policy code, route dispatch, LanguageSwitcher,
|
||
Header, styling, dependency versions/lockfile, environment or deployment
|
||
configuration are required. Existing audit-generated link/blog/image reports
|
||
are unchanged. Employee-portal implementation, the separate Ads project and
|
||
all unrelated files remain untouched. The pre-existing untracked
|
||
`merge-plan.md` retains SHA-256
|
||
`015db80cdbaf7d68799265d2070db760155c342b432ce6795f17ebc2218c641c`.
|
||
|
||
No blocking Phase 3A/3B defect was found. Deferred work includes broader title,
|
||
content and image-alt reconciliation, regional social locale decisions,
|
||
article/FAQ schema, and human language review where substantive translations
|
||
change. No Phase 4B work or commit is authorized by this implementation review.
|
||
|
||
## Phase 4B — Article and FAQ Structured Data (2026-10-08)
|
||
|
||
Implemented on `faithful-astro-migration`, starting from
|
||
`4ed01d7d288b249bd028a492e534d3d91adad6f7`. The working tree initially contained
|
||
only the unrelated untracked `merge-plan.md`. The current history has the
|
||
Phase 4A change set after two Ads documentation commits; this phase does not
|
||
alter or incorporate that handoff work. Earlier milestone sections remain
|
||
historical evidence. Nothing in this phase is staged or committed.
|
||
|
||
### Existing Implementation and New Production Evidence
|
||
|
||
Inspection covered BlogPostLayout, BaseLayout, FAQAccordion, FaqPage, all FAQ
|
||
component consumers, content schemas, the three author records, publication
|
||
helpers, the existing SEO tests, and the plan's Phase 4B acceptance criteria.
|
||
The initial generated artifact had 96 routes, one existing MedicalOrganization
|
||
block per route, no BlogPosting blocks, and 20 FAQPage blocks: 125 questions in
|
||
19 English/Spanish MDX articles and two insurance questions. Those 127 schema
|
||
answers matched their rendered answers after whitespace normalization.
|
||
|
||
`/faqs` was different: its rendered Markdown/MDX source contained 70 unique
|
||
direct H3 questions, but FAQAccordion received no `items`. Browser code grouped
|
||
the H3s and following siblings into accordions at runtime, so the server emitted
|
||
no FAQPage. This was a missing schema path, not a reason to replace the working
|
||
accordion, its interaction code, or its content.
|
||
|
||
Nine read-only production GETs on **2026-10-08 21:57:43–21:57:53 UTC** comprised
|
||
robots first and the eight targeted pages below. Robots allowed these paths;
|
||
all responses were HTTP 200, requests were at least one second apart, and no
|
||
redirects were followed. No forms, APIs, production writes or broad crawl were
|
||
used. Production HTML stayed in temporary storage.
|
||
|
||
| Production page | Observation UTC | Relevant findings |
|
||
| --- | --- | --- |
|
||
| [English self-advocacy](https://www.azinstitute4autism.com/library/autism-self-advocacy-skills-aba) | 21:57:44 | BlogPosting headline uses the SEO title, not display H1; Rula Diab author; published `2024-12-02T07:00:00.000Z`, modified `2026-10-03T20:47:43.625Z` |
|
||
| [Spanish self-advocacy](https://www.azinstitute4autism.com/es/library/autism-self-advocacy-skills-aba) | 21:57:45 | BlogPosting, localized Rula Diab byline; published `2026-04-09T03:36:24.000Z`, modified `2026-04-09T03:36:32.552Z`; current visible date is April 9, 2026 |
|
||
| [Arabic self-advocacy](https://www.azinstitute4autism.com/ar/library/autism-self-advocacy-skills-aba) | 21:57:47 | BlogPosting, localized Rula Diab byline; published `2024-12-02T07:00:00.000Z`, modified `2025-09-09T01:34:16.718Z` |
|
||
| [Standalone FAQs](https://www.azinstitute4autism.com/faqs) | 21:57:48 | One FAQPage with 70 questions |
|
||
| [Insurance](https://www.azinstitute4autism.com/insurance) | 21:57:49 | One FAQPage with two questions; local question/answer text matches the production schema after normalization |
|
||
| [School readiness](https://www.azinstitute4autism.com/library/aba-school-readiness-arizona) | 21:57:51 | BlogPosting plus FAQPage with nine questions; local article has seven older questions |
|
||
| [Community interview](https://www.azinstitute4autism.com/library/community-highlight-meet-rula-diab) | 21:57:52 | `noindex`, external Voyage Phoenix canonical; HubSpot still supplies BlogPosting with AIA-logo publisher and Rula Diab author |
|
||
| [Office article](https://www.azinstitute4autism.com/library/new-aia-scottsdale-office) | 21:57:53 | `noindex`, external Scottsdale Airpark canonical; same generic HubSpot authorship/publisher pattern |
|
||
|
||
Current source checks support the shared metadata structure and selected
|
||
records; they do not certify the currency of all 65 local articles. Identified
|
||
date/copy drift is explicitly deferred below, not silently reconciled.
|
||
|
||
### Article Architecture and Publication Exceptions
|
||
|
||
`src/utils/structured-data.ts` holds the schema builders and an HTML-safe JSON
|
||
serializer. BlogPostLayout consumes the existing manifest publication record
|
||
and authors collection and emits one BlogPosting through BaseLayout's existing
|
||
head slot. BaseLayout's MedicalOrganization block is unchanged.
|
||
|
||
BlogPosting includes canonical `@id` (`#article`), `url`, `mainEntityOfPage`, the
|
||
existing SEO `title` as `headline`, language, declared publication day, and
|
||
optional nonblank description, featured image and explicit modification day.
|
||
Image resolution reuses Phase 4A's public-origin helper. Display H1 does not
|
||
replace the SEO title. No body text, keywords, publisher, credentials, original
|
||
publication claim or missing image is fabricated.
|
||
|
||
Author resolution requires exactly one record with the article's declared
|
||
author slug and language. Its `name` supplies a Person name. Missing/ambiguous
|
||
references fail, rather than silently substituting Rula Diab or an English
|
||
record. Existing authors all identify Rula Diab. Author URLs are omitted because
|
||
the repository does not yet generate author archives. No author records or
|
||
frontmatter/schema fields changed.
|
||
|
||
Dates use the precision actually supplied by current records: calendar days.
|
||
`updatedDate` is emitted only when explicitly present; all current records lack
|
||
it. Neither build time, Git dates nor recently observed HubSpot update times
|
||
are substituted. Modification before publication fails validation.
|
||
|
||
Both article and FAQ builders reuse the manifest's **record-level
|
||
`sitemapEligible`** gate. Drafts, noindex and external-canonical records emit
|
||
neither new type. The two syndicated articles above therefore receive no
|
||
invented original author/publisher claim, even though production HubSpot emits
|
||
generic article schema there. Their external canonicals, noindex and global
|
||
site organization block remain intact. `/schedule-consultation` and
|
||
`/employee-portal` likewise emit neither type; `/ar` remains unpublished.
|
||
|
||
The record gate is independent of `PUBLIC_ALLOW_INDEXING`. Eligible records
|
||
emit schema in both build modes for local testing, while staging retains its
|
||
global noindex protection, empty sitemap and absent hreflang. Schema does not
|
||
make a record indexable or create translation relationships.
|
||
|
||
### FAQ Verification and Corrections
|
||
|
||
FAQAccordion remains the single FAQ schema producer. Its existing supplied-item
|
||
markup, CSS, animation, search and runtime grouping code are preserved.
|
||
|
||
- Schema answers derive from the HTML actually rendered by the component,
|
||
using `answerHtml` when present or the same `answer` fallback. This prevents
|
||
a stale duplicate plain-text field from contradicting the visible answer.
|
||
Entity decoding and block separators preserve readable text; nonvisible
|
||
script/style/template and explicitly hidden nodes are excluded.
|
||
- FaqPage renders its existing slot once, displays that same HTML, and passes
|
||
it to FAQAccordion as `sourceHtml`. The builder groups direct H3 questions
|
||
and following siblings just as the unchanged browser enhancement does.
|
||
Nested H4/H5 headings and lists stay inside their answer. All 70 questions
|
||
are now described in server JSON-LD, including with JavaScript disabled.
|
||
- A runtime-only selector without server source emits no invented FAQ schema.
|
||
Supplied items cannot be mixed with a runtime source. Empty groups emit none.
|
||
- Schema IDs use the manifest canonical. Any retained component canonical prop
|
||
must agree with it; conflicting values fail. Existing canonical props and
|
||
article content are unchanged.
|
||
- Empty questions/answers and duplicate questions fail. A request-scoped
|
||
`Astro.locals` claim rejects a second FAQ schema-producing accordion on the
|
||
same page. Separate rendered pages do not share this state. Existing
|
||
organization, article and FAQ blocks coexist with distinct entity IDs.
|
||
- JSON-LD escapes `<` so script-like text cannot terminate its HTML script
|
||
element. This is exercised in both helper and rendered-article fixtures.
|
||
|
||
Result: **21 FAQPage blocks, 197 questions** (125 article, two insurance, 70
|
||
standalone), and **63 BlogPosting blocks** (65 articles minus two syndicated
|
||
exceptions). No unrelated schema types or new organization entities were added.
|
||
|
||
### Date-Display Defect Found During Validation
|
||
|
||
The build host uses `America/Phoenix`. Existing article/card date formatting
|
||
converted date-only frontmatter through that timezone: declared `2024-12-02`
|
||
appeared as December 1 despite the machine-readable time retaining December 2.
|
||
That would make the new schema disagree with the displayed calendar day.
|
||
|
||
The minimal correction adds `timeZone: 'UTC'` to the two existing article/card
|
||
formatters. It preserves declared dates, formatting options and locale, and
|
||
does not update any article to match a newer production publication date. On
|
||
this host it corrects **130 labels**: 65 article dates and 65 Library-card dates.
|
||
SEO tests explicitly build under `America/Phoenix` and compare both visible
|
||
formats with each record's declared date in all three languages. This is a
|
||
rendering-consistency fix within Phase 4B, distinct from Phase 6C date research.
|
||
|
||
### Phase 6C Drift and Remaining Uncertainty
|
||
|
||
- Spanish self-advocacy still declares `2024-12-02` locally, while the current
|
||
production article declares/displays April 9, 2026. Its local publication
|
||
record was not rewritten. Reconcile translation publication history in
|
||
Phase 6C; do not mistake the timezone repair for this separate correction.
|
||
- English school-readiness has seven older local FAQ items around the former
|
||
academy/program description. Production has nine questions about current
|
||
school-readiness skills and ABA's relationship to school. Its shared academy
|
||
question also has a different answer. Title/content/FAQ reconciliation stays
|
||
in Phase 6C; no answers or Library bodies changed here.
|
||
- Production article modification timestamps and localized bylines are richer
|
||
than current local records. They were observed but not imported into otherwise
|
||
unreconciled records. No claim of full current-content parity is made.
|
||
- The 70 standalone questions are derived from actual rendered local source.
|
||
Text extraction shows punctuation/HTML-spacing differences from production;
|
||
this milestone is not a sentence-by-sentence clinical/content review.
|
||
|
||
Schema.org still defines [BlogPosting](https://schema.org/BlogPosting) and
|
||
[FAQPage](https://schema.org/FAQPage). Google's
|
||
[article documentation](https://developers.google.com/search/docs/appearance/structured-data/article)
|
||
supports applicable, source-backed properties without requiring fabricated
|
||
optional fields. Its [current changelog](https://developers.google.com/search/updates)
|
||
records removal of FAQ rich results beginning May 7, 2026 and removal of that
|
||
feature's documentation in June. This implementation preserves semantic FAQ
|
||
markup and source fidelity; it makes no promise of Google FAQ rich results.
|
||
|
||
The browser tool returned `Transport closed`, so interactive desktop/mobile
|
||
checks could not run. The accordion's client code and CSS are unchanged, and
|
||
all-route rendered comparisons verify content/markup, scripts and style content.
|
||
Browser interaction/visual confirmation and external rich-result tooling remain
|
||
manual checks; no remote validator submission or deployment was performed.
|
||
|
||
### Validation and Artifact Invariants
|
||
|
||
Final `npm run test:seo`: **22 passed**, comprising the 12 Phase 4A tests plus
|
||
10 structured-data/date tests. Coverage includes en/es/ar articles, absent
|
||
optional metadata, declared/modified dates, exact author resolution, noindex,
|
||
external canonical and draft exclusions, every rendered FAQ answer, the
|
||
standalone runtime source, empty/unknown sources, multiple JSON-LD blocks,
|
||
duplicate/conflicting schema failures, safe serialization and timezone behavior.
|
||
`npm run test:publication`: **33 passed** with no changes to that suite.
|
||
|
||
An initial standalone-FAQ assertion incorrectly compared sibling text without
|
||
block-boundary whitespace. The assertion was corrected and extraction now
|
||
explicitly preserves block separators. After the date-display defect was found
|
||
and fixed, the full tests/build/audit sequence was rerun successfully:
|
||
|
||
```sh
|
||
cd www
|
||
npm run test:seo
|
||
npm run test:publication
|
||
npm run build
|
||
PUBLIC_ALLOW_INDEXING=true npm run build
|
||
npm run audit:routes -- --offline
|
||
npm run audit:routes -- --check
|
||
npm run audit:links
|
||
npm run audit:blog
|
||
npm run audit:images
|
||
npm run build
|
||
npm run audit:routes -- --offline
|
||
npm run audit:routes -- --check
|
||
git diff --check
|
||
```
|
||
|
||
Both normal builds and the indexing-enabled build checked 74 files with zero
|
||
errors, warnings or hints. Link, blog and mapped-image audits each reported
|
||
zero failures. All selected article schema images resolve to local public assets.
|
||
|
||
| Final artifact | Verified UTC, 2026-10-08 | HTML routes | Sitemap URLs | Robots | Hreflang |
|
||
| --- | --- | ---: | ---: | --- | --- |
|
||
| Indexing-enabled local | 22:21:40 | 96 | 92 | 92 `index,follow`; four `noindex,follow` | 174 links on 53 routes, unchanged 24 sets |
|
||
| Normal staging, restored | 22:22:24 | 96 | 0 | All 96 `noindex,nofollow` | Zero links |
|
||
|
||
The route set remains 67 English, 21 Spanish and eight Arabic. All 96 canonicals,
|
||
non-schema metadata, H1s, HTML language/direction and translation choices match
|
||
the starting artifact/policy. Existing MedicalOrganization objects match on
|
||
all 96 routes. Body markup and scripts match after accounting for the explicit
|
||
date-label fix, added JSON-LD, whitespace and pre-existing random contact IDs.
|
||
All inline CSS declarations and stylesheet URLs are unchanged. Astro moved the
|
||
unchanged FAQ stylesheet link relative to an unrelated inline insurance-style
|
||
block after making FAQ rendering asynchronous; no selectors/declarations changed.
|
||
|
||
The final durable evidence is
|
||
[`route-reconciliation-2026-10-08-offline-22-22-25-260Z.json`](route-reconciliation-2026-10-08-offline-22-22-25-260Z.json).
|
||
It reuses all 70 historical discovery requests with their observation times.
|
||
Route rows/totals remain unchanged: 129 discovered routes, historical production
|
||
sitemap 102, local generated 96, overlap 92, and ten historical sitemap routes
|
||
missing locally. Intermediate indexing evidence stayed in temporary storage;
|
||
the prior committed audit evidence remains intact. No fresh crawl was made to
|
||
refresh fingerprints; the targeted schema observations above are separately dated.
|
||
|
||
### Read-only Structural Review
|
||
|
||
The complete Phase 4B change set has nine files, all relative to `www/`:
|
||
|
||
| Classification | File | Purpose |
|
||
| --- | --- | --- |
|
||
| Structured-data core, new | `src/utils/structured-data.ts` | Publication-gated builders, author validation, visible FAQ extraction, safe JSON serialization |
|
||
| Article presentation/schema | `src/layouts/BlogPostLayout.astro` | Typed article entry, head-slot BlogPosting, calendar-day formatting |
|
||
| Date presentation | `src/components/BlogCard.astro` | Same calendar-day correction for Library cards |
|
||
| Existing FAQ producer | `src/components/FAQAccordion.astro` | Shared builder, manifest canonical validation, rendered-source support, duplicate guard; client script/styles unchanged |
|
||
| Runtime FAQ source bridge | `src/components/pages/FaqPage.astro` | Render slot once for both visible source and server schema |
|
||
| Regression coverage | `tools/seo.test.mjs` | Extend existing actual-Astro tests; no parallel publication policy |
|
||
| Editing documentation | `README.md` | Schema/date/FAQ rules and known reconciliation boundaries |
|
||
| Milestone evidence | `reports/migration-summary.md` | This dated implementation and review record |
|
||
| Offline evidence, new | `reports/route-reconciliation-2026-10-08-offline-22-22-25-260Z.json` | Final source fingerprint with preserved production discovery |
|
||
|
||
No content/frontmatter records, content schemas, dependencies, publication or
|
||
translation policy, routing, deployment files, employee-portal work or Ads
|
||
handoff files were modified. `merge-plan.md` remains untracked and unchanged,
|
||
SHA-256 `015db80cdbaf7d68799265d2070db760155c342b432ce6795f17ebc2218c641c`.
|
||
There is no new blocking policy question; Phase 6C must resolve the documented
|
||
content/date drift. Stop for implementation/diff acceptance before any checkpoint
|
||
commit. Phase 5A has not started.
|
||
|
||
## Phase 5A — Services, Referrals, and Consultation (2026-10-09 UTC)
|
||
|
||
Implemented from Phase 4B checkpoint
|
||
`4079156776dd6b5a1b4e42b02dd9f680944484dd` on
|
||
`faithful-astro-migration`. This section records the implementation and read-only
|
||
review; nothing is staged or committed. The shell's actual UTC retrieval date
|
||
was October 9. AIA's governing editorial confirmation is dated **October 8,
|
||
2026**, as supplied by the user. Earlier reports and production observations
|
||
remain historical evidence, not competing authority for the confirmed correction.
|
||
|
||
### Scope, Authority, and Source Freshness
|
||
|
||
Inspected all seven English primary pages and all six existing Spanish
|
||
counterparts: ABA therapy, autism evaluations, Learner Social Club, services,
|
||
client consultation, intake, and English referrals. No Spanish referrals record
|
||
exists; none was created. Also inspected English schedule consultation and
|
||
insurance; FormShell, ServiceInquiryDrawer, ServicesPage, PageLayout, Button,
|
||
shared service data and relevant navigation/CTA code. Publication, translation,
|
||
heading, social and structured-data infrastructure was inspected and retained.
|
||
|
||
AIA explicitly confirmed general ABA eligibility as **18 months through 8
|
||
years / 18 meses a 8 años** and superseded broader children/teens descriptions.
|
||
This decision governs the in-scope edits even when cached production content
|
||
conflicts. It is resolved, not a human-decision blocker. It does not establish
|
||
ages for the Academy, Social Club or diagnostic evaluations.
|
||
|
||
Durable new source evidence:
|
||
[`phase-5a-source-evidence-2026-10-09.json`](phase-5a-source-evidence-2026-10-09.json).
|
||
It records exact URLs, request times, HTTP status, request/response cache
|
||
indicators, body hashes, titles, descriptions, H1s, canonicals, selected source
|
||
excerpts and CTA destinations. It contains no complete HTML captures or cookies.
|
||
|
||
There were **23 successful read-only GETs**: AIA robots, 15 targeted AIA pages,
|
||
four cache rechecks, Jotform robots and two bare Jotform destination status
|
||
checks. Page requests were sequential with at least 1.1 seconds between them;
|
||
redirects were not followed. AIA robots allowed the selected paths. Jotform
|
||
robots permits the bare numeric paths; its disallowed tracking-query form
|
||
variant was not fetched. No scripts, forms, APIs, authenticated operations,
|
||
tracking endpoints or production writes were executed. A web-tool robots
|
||
attempt failed before the successful direct retrieval. The independent browser
|
||
attempt failed with `Transport closed`; no browser response was obtained.
|
||
|
||
Every AIA page request sent `Cache-Control: no-cache, max-age=0` and
|
||
`Pragma: no-cache`. Responses still carried Cloudflare/HubSpot cache indicators:
|
||
`Cache-Control: s-maxage=36000, max-age=5` and
|
||
`X-HS-Cache-Control: s-maxage=36000, max-age=0`. `Age`, page `ETag` and
|
||
`CF-Cache-Status` were absent; `X-HS-CF-Cache-Status`, `Last-Modified`,
|
||
`X-HS-Prerendered`, response Date and CF-Ray are saved where available.
|
||
Prerender dates matched Last-Modified. **HTTP 200, MISS and REVALIDATED do not
|
||
prove that the underlying prerendered content contains the newest edits.**
|
||
|
||
Initial source observations (all times UTC, October 9, 2026):
|
||
|
||
| Source URL | Request time | HTTP | X-HS-CF-Cache-Status | Last-Modified (GMT) |
|
||
| --- | --- | ---: | --- | --- |
|
||
| [/aba-therapy](https://www.azinstitute4autism.com/aba-therapy) | 01:26:21 | 200 | HIT | Sat, 03 Oct 2026 23:27:01 GMT |
|
||
| [/autism-evaluations](https://www.azinstitute4autism.com/autism-evaluations) | 01:26:22 | 200 | HIT | Sat, 03 Oct 2026 23:13:18 GMT |
|
||
| [/learner-social-club](https://www.azinstitute4autism.com/learner-social-club) | 01:26:23 | 200 | HIT | Sat, 03 Oct 2026 23:13:14 GMT |
|
||
| [/services](https://www.azinstitute4autism.com/services) | 01:26:25 | 200 | HIT | Sat, 03 Oct 2026 23:13:23 GMT |
|
||
| [/referrals](https://www.azinstitute4autism.com/referrals) | 01:26:26 | 200 | HIT | Sat, 03 Oct 2026 23:45:35 GMT |
|
||
| [/client-consultation](https://www.azinstitute4autism.com/client-consultation) | 01:26:28 | 200 | HIT | Sun, 04 Oct 2026 00:00:00 GMT |
|
||
| [/aba-therapy-intake-process](https://www.azinstitute4autism.com/aba-therapy-intake-process) | 01:26:29 | 200 | HIT | Sat, 03 Oct 2026 23:13:15 GMT |
|
||
| [/es/aba-therapy](https://www.azinstitute4autism.com/es/aba-therapy) | 01:26:30 | 200 | HIT | Sat, 03 Oct 2026 23:13:14 GMT |
|
||
| [/es/autism-evaluations](https://www.azinstitute4autism.com/es/autism-evaluations) | 01:26:32 | 200 | MISS | Sat, 03 Oct 2026 23:13:12 GMT |
|
||
| [/es/learner-social-club](https://www.azinstitute4autism.com/es/learner-social-club) | 01:26:33 | 200 | MISS | Sat, 03 Oct 2026 23:13:22 GMT |
|
||
| [/es/services](https://www.azinstitute4autism.com/es/services) | 01:26:35 | 200 | REVALIDATED | Sat, 03 Oct 2026 23:13:22 GMT |
|
||
| [/es/client-consultation](https://www.azinstitute4autism.com/es/client-consultation) | 01:26:36 | 200 | REVALIDATED | Sun, 04 Oct 2026 00:00:44 GMT |
|
||
| [/es/aba-therapy-intake-process](https://www.azinstitute4autism.com/es/aba-therapy-intake-process) | 01:26:38 | 200 | MISS | Sat, 03 Oct 2026 23:13:18 GMT |
|
||
| [/schedule-consultation](https://www.azinstitute4autism.com/schedule-consultation) | 01:26:39 | 200 | REVALIDATED | Sat, 03 Oct 2026 23:13:23 GMT |
|
||
| [/insurance](https://www.azinstitute4autism.com/insurance) | 01:26:41 | 200 | HIT | Sat, 03 Oct 2026 23:13:18 GMT |
|
||
|
||
Rechecks at 01:28:06–01:28:10 used the same headers and the permitted unique
|
||
query `?migration_review=20261009T0130` on `/aba-therapy`, `/es/aba-therapy`,
|
||
`/client-consultation` and `/schedule-consultation`. All four returned HIT with
|
||
identical extracted text and metadata to their initial responses. This does
|
||
not guarantee an origin refresh. In particular, schedule consultation still
|
||
returned “children and teens,” contradicting the newer AIA instruction; it is
|
||
classified as potentially stale. Other responses corroborate the approved ABA
|
||
ages and removal of teens from both client-consultation pages. Origin freshness
|
||
remains inconclusive overall. No production change is inferred from response
|
||
status alone.
|
||
|
||
### Page-by-page Reconciliation
|
||
|
||
In this table, **P** means a newly retrieved production response with origin
|
||
freshness inconclusive (see the exact request time above). **E** means AIA's
|
||
confirmed October 8 editorial instruction. P/E records do not assert cache
|
||
bypass success. CTA resolutions are detailed separately below.
|
||
|
||
| Route / language | Claim or element | Previous Astro state | Retrieved production state | Editorial requirement | Source time / freshness | Resolution and notes |
|
||
| --- | --- | --- | --- | --- | --- | --- |
|
||
| `/aba-therapy` en | Individual 1:1 age | “children aged 2 to 8 years” | “children aged 18 months to 8 years” | “18 months through 8 years” | P 01:26:21 + E; origin inconclusive, decision confirmed | Changed to “children aged 18 months through 8 years” |
|
||
| `/aba-therapy` en | Section heading | “Behavioral Services We Offer” | “Services We Offer” | — | P 01:26:21; origin inconclusive | Changed label; explicitly retain `behavioral-services-we-offer` ID to preserve existing fragment URLs |
|
||
| `/aba-therapy` en | Group program | 1:2 Academic Readiness, ages 2–6, AIA Preparatory Academy© | Same distinct program, ratios, range and branding | General age rule does not override this program | P 01:26:21 | Retained paragraphs, electives and 2–6 range; no clinical claims added |
|
||
| `/es/aba-therapy` es | General/1:1 eligibility | “personas de 2 a 17 años de edad, que han sido diagnosticadas”; “niños de 2 a 8 años” | General introduction says children; 1:1 says “niños de 18 meses a 8 años” | “18 meses a 8 años” | P 01:26:30 + E | Changed introduction to “niños de 18 meses a 8 años de edad, que han sido diagnosticados” and 1:1 to approved age phrase; preserves paragraph structure |
|
||
| `/es/aba-therapy` es | Academy branding | Link label “Academia Preparatoria AIA©” | Proper name “AIA Preparatory Academy©” | — | P 01:26:30; origin inconclusive | Use source-supported proper name; retain existing `https://aiaprep.org/` destination and 2–6 group-program range |
|
||
| `/autism-evaluations` en | Meta description | Ends at “support your child” | Ends at “support your child's unique development.” | — | P 01:26:22; origin inconclusive | Restore the complete source description; title and H1 unchanged |
|
||
| `/autism-evaluations` en; `/es/autism-evaluations` es | Diagnostic services | Separate ASD, ADHD and combined evaluation; ADOS discussion | Same offerings and clinical descriptions | Do not inherit ABA ages | P 01:26:22 / 01:26:32 | Body retained. “Children of all ages” describes the tool; it is not verified clinic eligibility. No clinic age limits, staffing or prerequisites invented |
|
||
| `/learner-social-club` en; `/es/learner-social-club` es | Age, schedule, payment and enrollment | Ages 8–17; 4–6 PM Mon/Wed or Wed; private pay; potty training; 30-day pause notice; one-day trial by email | Matches retrieved page content and metadata in each language | Separate program | P 01:26:23 / 01:26:33 | All facts retained. Only enrollment CTA destination changes; availability still requires confirmation before activation |
|
||
| `/services` en; `/es/services` es | Services, geography/options and clinical copy | In-center/school/home, early intervention, academic readiness, supervision, parent consultation; “1 in 36 … each year” | Matches retrieved content, including the prevalence wording | Do not manufacture service availability | P 01:26:25 / 01:26:35 | Retained. English body is owned by ServicesPage, not its MDX slot. No need to edit either English duplicate. Clinical statistic held for review rather than silently replacing it |
|
||
| `/es/services` es | Home breadcrumb | `/` | `/es/?hsLang=es` | Keep published language routing | P 01:26:35 | Changed to `/es`; existing Spanish service/consultation links remain localized, rather than copying production English paths with `hsLang=es` |
|
||
| `/referrals` en | Referral audience | “educational and therapeutic programs for children ages 2-17” | Same sentence with “18 months to 8 years” | Confirmed range is general ABA, not every program | P 01:26:26 + E | “ABA therapy programs for children ages 18 months through 8 years”; explicitly limits the claim to ABA. Existing provider/insurer collaboration and reporting descriptions retained |
|
||
| `/client-consultation` en | Audience/introduction | “Here at”; two “children and teens” references | “At”; both references say “children” | Approved ABA age and audience | P 01:26:28 + E | Source intro “At”; remove teens; ABA services sentence specifies “children aged 18 months through 8 years.” No-wait-list and existing Phoenix-area geography retained pending operational confirmation |
|
||
| `/es/client-consultation` es | Audience | Two “niños y adolescentes” references | Both say “niños” | Approved Spanish ABA age/audience | P 01:26:36 + E | Remove “y adolescentes”; ABA sentence specifies “niños de 18 meses a 8 años.” Remaining Spanish copy unchanged |
|
||
| `/aba-therapy-intake-process` en; `/es/aba-therapy-intake-process` es | Intake steps and CTA | Six steps; verification of insurance, copays and required authorizations; final label is plain text | Same six-step process with final consultation link | No new universal prerequisites | P 01:26:29 / 01:26:38 | Steps and insurance wording retained; restore styled linked CTA using existing local consultation pages. No intake packet/submission functionality added |
|
||
| `/schedule-consultation` en | Audience | Two “children and teens” references | Same superseded wording despite recheck | E overrides stale response | P 01:26:39 / recheck 01:28:10, potentially stale + E | Remove teens and explicitly state ABA age range in ABA services sentence. Retain noindex, existing geography/contact details and disabled form; do not treat response as fresh editorial authority |
|
||
| `/insurance` en | Plans/payment and FAQ | Logo list and existing ECHO/ESA FAQ claims | Same visible carrier logos/FAQ text | No plan-to-plan generalization | P 01:26:41; origin inconclusive | Unchanged; independently compared this page rather than assuming service/form fields establish every plan's coverage. Participation/coverage details remain unverified |
|
||
|
||
No article, FAQ answer, homepage, team or portal content was changed. No new
|
||
Spanish records, translations or translation keys were introduced. All page
|
||
titles and visible H1s remain unchanged. The evaluation description is the only
|
||
frontmatter value changed. Changes to metadata values use the existing SEO
|
||
pipeline; no schema-generation rule or organization data changed.
|
||
|
||
### CTA Reconciliation and Disabled Forms
|
||
|
||
Bare production Jotform destinations `231638510219149` and `250727122848156`
|
||
returned HTTP 200 at 01:30:34 and 01:30:35 respectively. These were GET status
|
||
checks only, with response bodies/scripts unused; availability does not approve
|
||
collection or establish form field/backend equivalence. The referral query
|
||
variant was not requested because of Jotform robots policy.
|
||
|
||
| Route(s) | Production label / destination | Previous Astro label / destination | Implemented migration destination / verification | Integration dependency |
|
||
| --- | --- | --- | --- | --- |
|
||
| `/aba-therapy`, `/autism-evaluations` | “Make an Appointment” → `https://form.jotform.com/231638510219149` | Same label and external URL | Same label → `/client-consultation`; generated destination exists, live consultation 200 | Existing disabled consultation shell; this is an inquiry path, not a booked appointment |
|
||
| `/es/aba-therapy` | “Hacer una cita” → same Jotform | Same label as unlinked text | Same label → `/es/client-consultation`; generated/live 200 | Same disabled shell; human Spanish form review still needed |
|
||
| `/es/autism-evaluations` | “Programar una cita” → same Jotform | Same label as unlinked text | Same label → `/es/client-consultation`; generated/live 200 | Evaluation intake/backend not implemented |
|
||
| Both Learner Social Club routes | “Enroll Now” → same Jotform (English label also on Spanish production) | Same label/external URL | Same label → corresponding English/Spanish consultation page; both resolve | Does not enroll or reserve a place; backend and service-specific process remain gated |
|
||
| Both Social Club routes, trial inquiry | One-day trial via obfuscated `info@azinstitute4autism.com` | Same address/ContactObfuscation behavior | Retained; no email sent | Trial availability must be confirmed by AIA |
|
||
| `/services` | “Consult with a Client Advocate” / “Get a Free Consultation” → `/client-consultation?hsLang=en` | Same labels → `/client-consultation` | Retained normalized local destination; resolves | Disabled consultation shell |
|
||
| `/es/services` | “Consulte con un Defensor del Cliente” → `/es/client-consultation?hsLang=es`; “Programe una consulta gratuita” → English path with `hsLang=es` | Both labels → `/es/client-consultation` | Retain existing real Spanish destination; resolves | Do not guess language from a query parameter |
|
||
| `/referrals` | “Refer a Client” → `https://form.jotform.com/231638510219149?hsCtaAttrib=203953990377` | Unlinked “Refer a Client”; existing disabled FormShell below | Same label → `#form-title`; exactly one matching element in generated page | Safe static referral placeholder; clinical referral workflow/required fields still need approval |
|
||
| Both intake routes | “Take the First Step” → `/client-consultation?hsLang=en` or `?hsLang=es` | Same unlinked label | `/client-consultation` or `/es/client-consultation`; both resolve | Starts inquiry, does not submit the described learner packet |
|
||
| Both client-consultation routes | Embedded Jotform `250727122848156` | Disabled local FormShell | Unchanged disabled shell; no embed, submit or success state added | Production form/backend/privacy approval outstanding |
|
||
| `/schedule-consultation` and service drawers | Production HubSpot/runtime form behavior; not executed | Disabled forms and call fallback | Retained; submission buttons disabled, no action destination, existing preventDefault handlers | Field parity, availability, clinical routing and backend require separate scoped activation |
|
||
|
||
The intentional temporary deviation is routing conversion links to existing
|
||
local disabled inquiry pages instead of third-party lead collection. Existing
|
||
form text explicitly states “Online submission is not yet connected” and offers
|
||
the existing phone fallback. No functioning submission is implied by the target.
|
||
Buttons retain source labels (including untranslated labels already present in
|
||
Spanish production); no new marketing or translation wording was invented.
|
||
|
||
Five `.md` records became `.mdx` because they now genuinely embed the existing
|
||
Button component: English referrals and intake, Spanish ABA, evaluations and
|
||
intake. Their collection IDs/slugs/public routes do not change. No routing or
|
||
layout conditionals were added. Existing Button styling is reused. FormShell,
|
||
ServiceInquiryDrawer, client scripts, fields, privacy behavior and form handlers
|
||
are unchanged. Production promises about callbacks/availability are retained
|
||
as source copy, not enabled functionality; they need review before activation.
|
||
|
||
### Repository-wide Eligibility Language Audit
|
||
|
||
Searched the full application source (pages/blog/authors, frontmatter, schema,
|
||
components, shared data and navigation), plus CMS configuration, for hyphen/en
|
||
and em-dash ranges, “to”/“a”/“hasta,” ages/years/months, Spanish niños/adolescentes,
|
||
English children/teens and Arabic age/adolescent terms. A broad semantic pass
|
||
produced 204 candidate lines, including non-eligibility words in code. Context
|
||
review excludes biographies, testimonials, generic developmental examples,
|
||
clinical research ages and historical reports from current AIA eligibility
|
||
corrections. Prior reports and baseline JSON are preserved, not globally replaced.
|
||
Locations below refer to the Phase 4B starting checkpoint unless marked current.
|
||
|
||
| Classification | File / location (relative to `www/`) | Exact relevant wording | Meaning, resolution and assigned phase |
|
||
| --- | --- | --- | --- |
|
||
| Corrected within Phase 5A | `src/content/pages/en/aba-therapy.mdx:27` | “children aged 2 to 8 years” | ABA 1:1 → confirmed 18 months through 8 years |
|
||
| Corrected within Phase 5A | `src/content/pages/es/aba-therapy.md:12,24` (now `.mdx`) | “personas de 2 a 17 años de edad”; “niños de 2 a 8 años” | General ABA/1:1 → approved Spanish range and agreement |
|
||
| Corrected within Phase 5A | `src/content/pages/en/referrals.md:14` (now `.mdx`) | “programs for children ages 2-17” | Referral ABA eligibility → confirmed range, explicitly scoped to ABA |
|
||
| Corrected within Phase 5A | `src/content/pages/en/client-consultation.md:10,14` | “children and teens”; “ABA therapy for children and teens” | Remove superseded audience; explicit ABA range |
|
||
| Corrected within Phase 5A | `src/content/pages/es/client-consultation.md:10,14` | “niños y adolescentes”; “terapia ABA para niños y adolescentes” | Remove superseded audience; explicit approved Spanish range |
|
||
| Corrected within Phase 5A | `src/content/pages/en/schedule-consultation.mdx:33,37` | “children and teens diagnosed with autism” | Correct despite potentially stale retrieval; noindex retained |
|
||
| Legitimate program-specific requirement | Both ABA page records, group-program paragraph (en:37, es:34 before rename) | “children aged 2 to 6 years”; “niños de 2 a 6 años” | Academic Readiness 1:2, supported by separate live program sections; retained |
|
||
| Legitimate program-specific requirement | Both Social Club records, descriptions and en:43 / es:50 | “8–17 years”; “jóvenes de 8 a 17 años” | Club ages, separate from ABA; retained, with private-pay distinction |
|
||
| Legitimate program-specific requirement | `src/data/services.json:16` | “Social and emotional learning opportunities for children and teens.” | Sociological card links specifically to the 8–17 Club; not general ABA; retained |
|
||
| Potentially outdated, deferred to another phase | `src/content/pages/en/index.md:14,23` | “clinical care for children and teens who have an autism diagnosis”; “ABA Therapy Services for Children and Teens Diagnosed with Autism Spectrum Disorder” | General ABA/homepage claims; **Phase 5B**, untouched |
|
||
| Potentially outdated, deferred to another phase | `src/content/pages/es/index.md:14,23` | “atención clínica experta para niños y adolescentes con diagnóstico de autismo”; “Servicios de terapia ABA para niños y adolescentes diagnosticados con TEA” | Spanish homepage general ABA claims; **Phase 5B**, source/language review in **Phase 7** as needed; untouched |
|
||
| Potentially outdated, deferred to another phase | `src/content/blog/en/aba-therapy-summer-routine-tips.mdx:20,149` | “resources tailored for children ages 2–17”; “In-clinic ABA therapy for children ages 2–8” | General AIA/ABA claims; **Phase 6C**. Club-specific “In-clinic Social Learners Club for ages 8-17” at :151 is separate and retained |
|
||
| Potentially outdated, deferred to another phase | `src/content/blog/en/community-highlight-meet-rula-diab.md:31,33,39` | “clinical care for children and teens diagnosed with Autism Spectrum Disorders”; “Our range of services for children and teens includes:”; “ABA Therapy Services for Children & teens” | Syndicated interview/ABA claims; **Phase 6C**, including original-source/editorial treatment; external canonical and noindex preserved |
|
||
| Potentially outdated, deferred to another phase | `src/content/blog/en/aba-school-readiness-arizona.mdx:2,3,18,154,155` | “AIA Preparatory Academy (Ages 2–6)”; “We currently serve children ages 2 to 6 who are in their most critical years of early development.” | Academy-specific range is not automatically wrong, but article was rewritten live (Phase 4B evidence). **Phase 6C**, not globally changed to ABA range |
|
||
| Potentially outdated, deferred to another phase | `src/content/blog/es/aba-school-readiness-arizona.mdx:2,3,18,72,154,155` | “Academia Preparatoria AIA (2 a 6 años)”; “Actualmente atendemos a niños de 2 a 6 años que se encuentran en sus años más críticos de desarrollo temprano.” | Same program/context distinction; **Phase 6C**, human language review/**Phase 7** where needed |
|
||
| Potentially outdated, deferred to another phase | `src/data/blog-footers.json:352,551` and `src/content/pages/es/library.md:14` | “Ya se inscriben alumnos: Academia Preparatoria AIA para niños de 2 a 6 años” | Related/popular Library titles reflecting the older article; **Phase 6C**, untouched |
|
||
| Potentially outdated, deferred to another phase | `src/data/blog-footers.json:629,749,948,959,1237,1657,1671,1724,1761` | “Now Enrolling: AIA Preparatory Academy for Children Ages 2–6” | Library links/title drift, not proof of wrong program eligibility; **Phase 6C** |
|
||
| Unresolved and requiring additional factual verification | `src/content/pages/en/tour.md:88` | “Learner Teen Group Area” | Room description may relate to the Club; no inference that ABA serves teens. Later scoped tour review, unchanged |
|
||
| Unresolved and requiring additional factual verification | `src/content/pages/en/client-forms.mdx:82,83` | “Step 4a: Print & Sign (Age 2 - 5)”; “Step 4b: Print & Sign (Ages 6+)” | Diagnostic paperwork bands, not general ABA eligibility; later forms/evaluation review, unchanged |
|
||
|
||
Context exclusions, deliberately not labeled ABA eligibility errors:
|
||
`en/faqs.mdx:34` discusses learners of any age and generic intervention evidence;
|
||
`en/early-signs-autism-by-age.mdx` discusses 12–24 months / 2–4 years;
|
||
en/es diagnostic-guide tables discuss 2–4 years;
|
||
en/es/ar executive-functioning articles discuss developmental stages including
|
||
adolescence (`en:82,96,110,112`; corresponding translated sections);
|
||
homepage testimonials mention starting at 21 months. No Arabic AIA ABA
|
||
eligibility claim matching the superseded range was identified. None of these
|
||
files was edited, and this screening is not a clinical or linguistic certification.
|
||
|
||
### Human-decision / Factual-verification Register
|
||
|
||
These are held questions for later reconciliation or activation, not reasons
|
||
to defer the already-confirmed ABA age correction:
|
||
|
||
| Area | Evidence / limitation | Current safe disposition and decision needed |
|
||
| --- | --- | --- |
|
||
| Program availability | Both ABA pages retain 2–6 Academic Readiness/Academy; both Club pages retain 8–17 and schedules; drawer claims enrollment open | Preserve distinct source-supported ranges. Confirm present enrollment, electives and schedules operationally before activating inquiries; do not infer closure or new ages from unrelated Library rewrites |
|
||
| Insurance participation | Insurance page shows BCBS, Aetna, Optum, Tricare, AHCCCS and United Healthcare logos. Local drawer specifically lists United Healthcare AHCCCS and additional payment choices; live runtime form fields were not executed/recovered | Logos do not prove all AHCCCS plans or all offered services are covered. Retain existing plan-specific wording; AIA billing must confirm exact networks, service coverage, authorizations, referrals and diagnostic prerequisites. No universal coverage rule added |
|
||
| Service geography / waits | Client pages claim no wait list and Phoenix-area coverage; schedule page additionally claims Tucson in-home service; its audience copy demonstrably conflicts with E | No new locations, wait times or staffing claims. Existing geography/wait copy held pending operational confirmation; inquiry drawer's guarantee language is also unverified, not strengthened |
|
||
| Clinical/evaluation claims | Services pages retain “1 in 36 … each year”; evaluations describe multidisciplinary teams and ADOS for children of all ages | Public page text is not independent clinical validation. Clinical owner should verify statistic/annual wording, actual evaluation staffing, accepted patient ages and referral/diagnosis requirements; no clinical replacement was invented |
|
||
| Referrals / intake | Production referrals uses a general Jotform; local generic FormShell cannot establish clinician referral fields or delivery workflow. Intake describes packets but has no functioning packet collection | Referral CTA exposes the disabled existing local form; intake goes to the local consultation page. Approve routing, required fields and privacy before backend activation; no successful referral or completed intake is implied |
|
||
| CTA/form backend | Production Jotform URLs resolve; local forms explicitly unavailable | Review the intentional local inquiry destinations as part of this milestone. Production collection, callback promises, backend choice and privacy approval remain separately gated; no Ads tags or analytics added |
|
||
| Contact freshness | Potentially stale schedule page retains `info@abaclinicaz.com`, whereas Club inquiry uses `info@azinstitute4autism.com` | Different addresses alone do not prove an error. Keep existing source-backed addresses, confirm intended consultation contact with AIA in a scoped follow-up |
|
||
|
||
### Multilingual Review Register
|
||
|
||
- **Explicitly approved wording:** Spanish ABA 1:1 and consultation now use
|
||
`18 meses a 8 años`. The ABA introduction replaces `personas ... diagnosticadas`
|
||
with `niños ... diagnosticados`, preserving grammatical agreement. Both
|
||
consultation references remove `y adolescentes`. These implement AIA's
|
||
approved correction, not invented translations. Have a human Spanish editor
|
||
review the revised sentences before publication; fluency is not self-approved.
|
||
- **Source-supported proper name:** `Academia Preparatoria AIA©` becomes
|
||
`AIA Preparatory Academy©`, matching Spanish production; no curriculum claim
|
||
or destination changed. Include this branding choice in language review.
|
||
- **Existing labels retained:** `Hacer una cita`, `Programar una cita`, `Enroll Now`
|
||
and `Take the First Step` match the corresponding production labels. The last
|
||
two remain English on Spanish pages; do not fabricate translations here.
|
||
- **Existing form limitation:** FormShell's explanatory copy/fields are English
|
||
even on the Spanish consultation route. No sourced Spanish form was available
|
||
from the unexecuted embed. Additional form localization belongs to a separately
|
||
supported review (Phase 7/form milestone), not speculative translation now.
|
||
- Spanish evaluation body, Club rules, intake steps and existing translations
|
||
otherwise remain intact. The services breadcrumb now correctly links to `/es`.
|
||
|
||
### Validation and Existing Test-harness Defect
|
||
|
||
The first `test:markdown` invocation failed in suite setup with
|
||
`Route is not published: /school-en`. Phase 4B's FAQ component resolves the
|
||
publication manifest from Astro.url, but the older Markdown test rendered real
|
||
FAQ-bearing content at synthetic aliases. An isolated copy of the **untouched
|
||
4079156 checkpoint** reproduced exactly the same failure. This was not caused
|
||
by the Phase 5A content changes.
|
||
|
||
The bounded correction is in `tools/markdown.test.mjs`: keep test aliases as
|
||
lookup keys but render each real record at its actual language/collection URL.
|
||
All original 20 assertions remain. No parser, FAQ, publication rule, route file
|
||
or application code was changed to make the test pass. No failure was ignored.
|
||
|
||
`tools/seo.test.mjs` adds four actual-Astro regression tests covering approved
|
||
general ABA ages/audiences, retained program ranges/ratios/payment distinctions,
|
||
14 CTA/breadcrumb cases with real route/fragment targets, disabled forms,
|
||
language/direction, one H1 and the repaired evaluation description. The existing
|
||
22 SEO tests and 33 publication tests remain. The old ABA section fragment is
|
||
also asserted. Tests use temporary copies; no fixture routes enter `dist`.
|
||
|
||
| Check | Final result |
|
||
| --- | --- |
|
||
| `npm run test:seo` | 26 passed; zero failures/skips |
|
||
| `npm run test:publication` | 33 passed; zero failures/skips |
|
||
| `npm run test:markdown` | 20 passed after the verified baseline fixture correction; zero failures/skips |
|
||
| `npm run build` (initial normal) | Passed; 96 HTML routes; zero Astro check errors/warnings/hints |
|
||
| `PUBLIC_ALLOW_INDEXING=true npm run build` | Passed; 96 routes, 92 sitemap URLs, 174 hreflang links across 53 pages |
|
||
| `npm run audit:routes -- --check` | Passed against newly generated offline evidence in each build mode |
|
||
| `npm run audit:links` | Zero broken internal links |
|
||
| `npm run audit:blog` | Zero blog content audit failures |
|
||
| `npm run audit:images` | Zero missing mapped page images |
|
||
| `npm run build` (final normal) | Passed; 96 routes, all `noindex,nofollow`, empty sitemap, no hreflang |
|
||
| `git diff --check` | Passed |
|
||
|
||
Source fingerprint refreshes used `npm run audit:routes -- --offline`, never a
|
||
new crawl. The final saved reconciliation is
|
||
[`route-reconciliation-2026-10-09-offline.json`](route-reconciliation-2026-10-09-offline.json).
|
||
All 70 historical discovery requests, original observation dates, baseline and
|
||
summary totals are preserved by deep comparison. Changed local rows reflect
|
||
five source-extension changes and the repaired description, not newly discovered
|
||
production routes. Historical totals remain 129 discovered route keys, 102
|
||
production-sitemap entries, 96 generated local routes, 92 overlaps and ten
|
||
historical sitemap routes missing locally. Do not confuse that historical
|
||
102-entry inventory with the current local 92-entry production-policy sitemap.
|
||
The intermediate indexing reconciliation is retained only under `/tmp`.
|
||
|
||
All-route generated HTML comparison against the starting staging artifact
|
||
confirmed identical route sets, canonicals, document titles, visible H1s,
|
||
HTML languages/directions, JSON-LD objects and header/language-switcher links.
|
||
All stable pre-existing main-content IDs remain; random contact-obfuscation IDs
|
||
are excluded. Visible prose differs only on the six eligibility/heading pages;
|
||
other edits change links or the one description without changing their labels.
|
||
There are no new images, styles, layout components or client scripts. MD-to-MDX
|
||
conversion preserves headings, paragraphs and lists apart from the documented
|
||
CTA conversion; existing styled Button markup is reused.
|
||
|
||
The indexing artifact was checked at **01:34:18 UTC**; the restored staging
|
||
artifact was independently checked at **03:33:00 UTC**. The later check time
|
||
reflects resumed work, not a new production observation. Production mode still
|
||
has 92 `index,follow` routes and the same four `noindex,follow` exceptions.
|
||
`/ar` remains unpublished, and all noindex/external-canonical exclusions persist.
|
||
All 63 BlogPosting, 21 FAQPage and 96 existing organization blocks are unchanged.
|
||
No publication, canonical, schema, robots, sitemap or translation policy changed.
|
||
|
||
Browser-level desktop/mobile validation could not run because the browser
|
||
transport was unavailable. Generated HTML, existing CSS reuse, one-H1/ID checks,
|
||
link and image checks support the content review; they do not certify visual
|
||
or interactive browser fidelity. No claim of completed pixel matching is made.
|
||
|
||
### Read-only Structural Review and File Inventory
|
||
|
||
There are **18 logical changed/new files**, including five `.md` → `.mdx`
|
||
conversions (23 paths in an unstaged status listing). All paths below are
|
||
relative to `www/`:
|
||
|
||
| Classification | Files | Why required |
|
||
| --- | --- | --- |
|
||
| English content | `src/content/pages/en/aba-therapy.mdx`, `autism-evaluations.mdx`, `client-consultation.md`, `learner-social-club.mdx`, `schedule-consultation.mdx` | Confirmed ABA facts, one source heading/description and safe local CTAs |
|
||
| English content conversions | `src/content/pages/en/referrals.md` → `.mdx`; `aba-therapy-intake-process.md` → `.mdx` | Use the existing Button component for previously inert CTA labels; referral range correction |
|
||
| Spanish content | `src/content/pages/es/client-consultation.md`, `learner-social-club.mdx`, `services.mdx` | Approved audience/age correction, local enrollment destination, localized breadcrumb |
|
||
| Spanish content conversions | `src/content/pages/es/aba-therapy.md` → `.mdx`; `autism-evaluations.md` → `.mdx`; `aba-therapy-intake-process.md` → `.mdx` | Approved ages/source branding and existing-label Button CTAs, with stable record identity |
|
||
| Regression coverage | `tools/seo.test.mjs`, `tools/markdown.test.mjs` | Four focused service tests; restore original Markdown suite compatibility with accepted Phase 4B |
|
||
| Dated evidence, new | `reports/phase-5a-source-evidence-2026-10-09.json` | Cache-aware targeted observations, separate from historical audit |
|
||
| Offline reconciliation, new | `reports/route-reconciliation-2026-10-09-offline.json` | Refresh local source evidence without rewriting production observations |
|
||
| Milestone report | `reports/migration-summary.md` | This reconciliation, audit, decisions, validation and review |
|
||
|
||
Reviewed changes do not touch dependencies, application configuration, shared
|
||
SEO/publication/translation/schema code, FormShell, ServiceInquiryDrawer,
|
||
ServicesPage, shared service data, homepage, Library, team, employee portal,
|
||
Ads handoff/landing pages, consent, analytics, deployment or Git configuration.
|
||
No routes, H1 fields or translation relationships were added. No forms were
|
||
activated, submitted or connected. No files are staged; no commit or push was
|
||
made. Phase 5B and all other reconciliation phases remain unstarted.
|
||
|
||
The existing untracked `merge-plan.md` remains unchanged, SHA-256:
|
||
`015db80cdbaf7d68799265d2070db760155c342b432ce6795f17ebc2218c641c`.
|
||
|
||
## Phase 5B — Homepage Content Reconciliation (2026-10-09 UTC)
|
||
|
||
Implemented on `faithful-astro-migration`, starting at the accepted Phase 5A
|
||
checkpoint `051fb7c1081614329dd65cf9e72a496d851b2c37`. This section records a
|
||
new observation and implementation milestone; it does not replace the earlier
|
||
audit or Phase 5A evidence. Scope is the English `/` and Spanish `/es` homepages,
|
||
their section model/components, focused tests and documentation. Detailed visual
|
||
fidelity remains Phase 8. No changes are staged or committed.
|
||
|
||
### Evidence, Dates and Cache Limitations
|
||
|
||
Evidence labels used below:
|
||
|
||
- **E — Implemented from confirmed AIA editorial requirements:** the user's
|
||
organizational confirmation dated **2026-10-08**: general ABA eligibility is
|
||
**18 months through 8 years / 18 meses a 8 años**; general ABA audience wording
|
||
referring to children and teens is superseded. This decision is resolved.
|
||
- **P — Implemented from production evidence:** exact content observed in this
|
||
phase's bounded public GET responses. Publication on the retrieved page is
|
||
verified; current origin freshness and underlying business eligibility are
|
||
not independently established.
|
||
- **R — Retained because current content is supported:** existing content matches
|
||
those retrieved responses, subject to the same cache limitations.
|
||
- **D — Deferred due to uncertainty:** needs factual/operational or language review.
|
||
- **O — Outside Phase 5B scope:** preserved for its assigned later milestone.
|
||
|
||
New machine-readable evidence:
|
||
[`phase-5b-source-evidence-2026-10-09.json`](phase-5b-source-evidence-2026-10-09.json).
|
||
It records exact URLs, UTC timestamps, status, selected cache headers, body
|
||
hashes, source metadata/headings, section order, important copy, lists, images
|
||
and alt text, CTA destinations, before/after field changes and output checks.
|
||
Raw HTML, cookies and broad production captures are not committed.
|
||
|
||
| Request | Retrieval UTC, 2026-10-09 | Status / cache evidence |
|
||
| --- | --- | --- |
|
||
| `https://www.azinstitute4autism.com/robots.txt` | 03:47:42 | 200; HIT; permits these homepage/asset requests; avoids disallowed preview/cache-buster paths |
|
||
| `https://www.azinstitute4autism.com/` | 03:48:03.652341 | 200; `X-HS-CF-Cache-Status: HIT`; Last-Modified and X-HS-Prerendered `2026-10-03 23:58:31 GMT` |
|
||
| `https://www.azinstitute4autism.com/es` | 03:48:05.022332 | 301 to `https://www.azinstitute4autism.com/es/`; Cache-Control `max-age=120` |
|
||
| `https://www.azinstitute4autism.com/es/` | 03:48:06.491271 | 200; HIT; Last-Modified and X-HS-Prerendered `2026-10-04 00:02:11 GMT` |
|
||
| `https://www.azinstitute4autism.com/?migration_review=20261009T0348` | 03:48:07.882981 | 200; HIT; byte-identical to first English response |
|
||
| `https://www.azinstitute4autism.com/es/?migration_review=20261009T0348` | 03:48:09.218681 | 200; HIT; byte-identical to first Spanish response |
|
||
| `https://www.azinstitute4autism.com/hubfs/hsa-fsa-accepted.png` | 03:51:40.337258 | 200 PNG; `CF-Cache-Status: HIT`; Age `1891407`; Last-Modified `2026-07-07 19:44:58 GMT`; ETag recorded in JSON |
|
||
|
||
Seven successful HTTP requests, including the redirect response and image;
|
||
no production writes, script execution, submissions, API calls or broad crawl.
|
||
Homepage requests were sequential, at least 1.1 seconds apart, with
|
||
`Cache-Control: no-cache, max-age=0` and `Pragma: no-cache`. HTML responses have
|
||
`Cache-Control: s-maxage=36000, max-age=5`,
|
||
`X-HS-Cache-Control: s-maxage=36000, max-age=0`, `Server: cloudflare` and CF-Ray
|
||
identifiers. Age, ETag and CF-Cache-Status were absent on those HTML responses.
|
||
The first web-retrieval attempt for robots failed; direct retrieval succeeded.
|
||
An independent browser attempt failed with `Transport closed`.
|
||
|
||
**Fresh retrieval is not proof of fresh origin content.** The English hero
|
||
still says “children and teens,” even though its services headings and metadata
|
||
have changed. The Spanish hero already says “niños,” but the duplicated
|
||
responsive services headings disagree: one still says “niños y adolescentes.”
|
||
AIA's E correction governs both local homepages. Query variants and no-cache
|
||
headers did not establish origin freshness; retries stopped after one recheck
|
||
per language. Other source-backed copy is carried forward with these limitations.
|
||
|
||
### English / Spanish Section Inventory and Resolution
|
||
|
||
All existing YAML sections were inspected, including headings, body text,
|
||
list order, image filenames/alt text and CTA references. Paragraph/list text
|
||
comparison normalized whitespace and typographic apostrophes; existing local
|
||
editorial formatting, descriptive alt text and historical quotations are retained.
|
||
No existing section was found to have been removed in either retrieved page.
|
||
|
||
| Order | Section | English comparison / resolution | Spanish comparison / resolution | Classification |
|
||
| --- | --- | --- | --- | --- |
|
||
| 1 | Hero | Preserve eyebrow, H1 markup, image, geography and CTA; remove “and teens” from body despite stale source | Preserve eyebrow, H1 markup, image, geography and CTA; remove “y adolescentes,” also matching source hero | E; remaining fields R |
|
||
| 2 | Services introduction / commitments | Replace old audience heading with ABA-specific approved age range; add source word “Treatment” to “Integrated Therapy”; retain five service items and seven commitment items/order | Replace old audience heading with approved Spanish range; retain five services, seven commitments, images and source-supported existing wording | E, P, R |
|
||
| 3 | Benefits | Heading, subheading, four benefits, video URL/title/image supported; retained | Own published wording, four benefits and same video retained | R |
|
||
| 4 | Skills | Six skills and icons/order supported; retained | Six existing translated labels/icons/order supported; retained | R |
|
||
| 5 | Insurance | Heading/body and six carrier logos supported; retained | Own heading/body and same six logos supported; retained | R, D for coverage verification |
|
||
| 6 | ESA | Heading, one paragraph, dollar range and ADE image supported; retained | Own published heading/paragraph and ADE image supported; retained | R, D for eligibility/amounts |
|
||
| 7 EN only | HSA/FSA | Missing locally; add exact published heading/paragraph and local copy of image, after ESA and before financial help | No equivalent in retrieved Spanish page; omit entirely | P; no invented translation |
|
||
| 8 EN / 7 ES | Financial help | Existing heading, uninsured assistance/pay-over-time paragraph and CTA supported; retained | Own existing heading, paragraph and CTA supported; retained | R, D for program availability |
|
||
| 9 EN / 8 ES | Process | Six cards present but inert locally; restore links and two incomplete source labels | Six source labels already match; restore links to Spanish intake headings | P; explicit local destination adaptation |
|
||
| 10 EN / 9 ES | Clinical director | Heading, quote, Rula Diab name/credentials/photo/signature supported; unchanged | Own published heading/quote/name/credentials preserved | R |
|
||
| 11 EN / 10 ES | Testimonials | Update heading “What Clients Are Saying” → “What Clients Say”; all 11 quotations/authors unchanged | Existing heading “Lo que dicen los clientes” and same 11 published English quotations unchanged | P for EN heading; R for quotes |
|
||
| 12 EN / 11 ES | BACB/CASP logos | Missing locally; restore unlinked image row immediately after testimonials | Same row published; restore with exact source alt text, which is English | P |
|
||
|
||
The logo row is inside production `<main>`, before the global footer, not a
|
||
footer redesign. Its images already exist locally. No invented membership or
|
||
certification paragraph, link or organization schema accompanies them.
|
||
|
||
### Exact Substantive Copy and Metadata Changes
|
||
|
||
All P observations refer to the two homepage timestamps above; E refers to
|
||
2026-10-08. Full previous/current field values are also in the evidence JSON.
|
||
|
||
| Route / field | Previous Astro | Resolution / source |
|
||
| --- | --- | --- |
|
||
| `/`, title | `ABA Therapy Near Me \| Arizona Institute for Autism \| Scottsdale` | P: `Scottsdale ABA Therapy for Children \| Arizona Institute for Autism` |
|
||
| `/`, description | `Arizona Institute for Autism: center for behavioral health & education services located in Scottsdale. We serve individuals with Autism and their families.` | P: `Arizona Institute for Autism: center for behavioral health & education services in Scottsdale. We serve children diagnosed with autism and their families.` |
|
||
| `/`, hero body phrase | `clinical care for children and teens who have an autism diagnosis` | E: `clinical care for children who have an autism diagnosis`; remaining sentence/geography untouched |
|
||
| `/`, services heading | `ABA Therapy Services for Children and Teens Diagnosed with Autism Spectrum Disorder` | E: `ABA Therapy Services for Children 18 Months Through 8 Years Diagnosed with Autism Spectrum Disorder`; production removes “and Teens,” while the explicit range comes from E |
|
||
| `/`, commitment item | `Integrated Therapy` | P: `Integrated Therapy Treatment` |
|
||
| `/`, process step 3 | `Fill and Sign an Intake Packet` | P: `Fill and Sign a Client Intake Packet` |
|
||
| `/`, process step 4 | `Verify Billing and Insurance` | P: `Verify Billing and Insurance Information and Benefits` |
|
||
| `/`, testimonials heading | `What Clients Are Saying` | P: `What Clients Say` |
|
||
| `/es`, hero body phrase | `atención clínica experta para niños y adolescentes con diagnóstico de autismo` | E + P: `atención clínica experta para niños con diagnóstico de autismo` |
|
||
| `/es`, services heading | `Servicios de terapia ABA para niños y adolescentes diagnosticados con TEA` | E: `Servicios de terapia ABA para niños de 18 meses a 8 años diagnosticados con TEA` |
|
||
|
||
Both visible H1s are unchanged: English `Behavioral Health & Special Education`
|
||
(with its existing line breaks) and Spanish `Salud Mental y Educación Especial`.
|
||
Spanish title and description remain its own published values; they were not
|
||
translated from the revised English metadata. The age range appears only in
|
||
ABA-specific headings, not imposed on evaluations, the Social Club or other
|
||
services. Historical testimonials, including the “21 months year old” statement,
|
||
are untouched. This resolves the four homepage findings deferred by Phase 5A;
|
||
its original eligibility audit remains intact as historical evidence.
|
||
|
||
### English HSA/FSA Implementation and Source Qualifications
|
||
|
||
Exact published heading:
|
||
**Health Savings Accounts (HSA) & Flexible Spending Accounts (FSA)**.
|
||
|
||
Exact substantive paragraph (only source nonbreaking whitespace normalized):
|
||
|
||
> Many families can also utilize their HSA and FSA to fund care, which allow you to pay for qualified clinical services using pre-tax dollars. The Arizona Institute for Autism (AIA) accepts Health Savings Account and Flexible Spending Account cards directly, making it easier to manage out-of-pocket costs for your learner's treatment. If you participate in one of these employer-sponsored or individual accounts, you can seamlessly apply your available funds toward tuition and fees for our ABA programs.
|
||
|
||
The optional `home.hsaFsa` content block uses `heading`, `body`, `image` and
|
||
`imageAlt`, validated through the existing Zod homepage model. Its dedicated
|
||
`HomeHsaFsa.astro` component renders after ESA/before financial help, matching
|
||
production: image left (5/12), text right (7/12), tinted background, one heading
|
||
and one paragraph. A single-column layout applies below 760px. The exact
|
||
500×425 source PNG is self-hosted as `public/assets/images/hsa-fsa-accepted.png`
|
||
(40,208 bytes), SHA-256
|
||
`25d1a0c6ed1e156e0861071fa409b5b6908b7f3b02407066a0d3b7014b25c195`.
|
||
Source alt `hsa-fsa-accepted` is preserved. The artwork itself says
|
||
“HSA APPROVED FSA”; it is published artwork, not an independent certification.
|
||
|
||
The qualifiers “Many families,” “qualified clinical services” and “If you
|
||
participate” are preserved. The section does not claim every expense is eligible,
|
||
provide a payment form, collect card data, load third-party scripts or add any
|
||
JSON-LD. Spanish has no `hsaFsa` block and renders no empty placeholder.
|
||
|
||
`home.logos` is a separate optional `items: [{ file, alt }]` block for the
|
||
observed final image row. Both optional sections are also supported by the
|
||
existing `sections:` discriminated union. Existing homepage records without
|
||
these blocks still render. `home.process.steps[].href` is optional; old steps
|
||
without destinations remain plain content. The existing process-card wrappers,
|
||
equal-height script, labels and styling remain except for accessible links and
|
||
focus indication. README documents all new editing fields.
|
||
|
||
### CTA Reconciliation
|
||
|
||
Production link labels/destinations are recorded verbatim in the evidence JSON.
|
||
No production form was submitted or activated. The four destination pages were
|
||
HTTP 200 in Phase 5A's **2026-10-09 01:26:28–01:26:38 UTC** observations; those
|
||
checks are explicitly inherited, not claimed as new Phase 5B retrievals.
|
||
Generated local destinations and every new fragment are checked by regression
|
||
assertions; all links/images pass local audits.
|
||
|
||
| CTA / locale | Production destination | Previous Astro | Intended Astro / verification |
|
||
| --- | --- | --- | --- |
|
||
| EN `Get Started`, `Schedule an Assessment` (commitments), `Request an Appointment` | `https://www.azinstitute4autism.com/client-consultation?hsLang=en` | Same labels, `/client-consultation` | Retain local route; all three links resolve; disabled form remains explicitly unavailable |
|
||
| ES `Empezar`, `Programar una evaluación` (commitments), `Solicitar cita` | `https://www.azinstitute4autism.com/client-consultation?hsLang=es` | Same labels, `/es/client-consultation` | Retain real Spanish route rather than copying the production English-path destination; disabled form remains unavailable |
|
||
| Six EN process cards | `/aba-therapy-intake-process#first-step` through `#sixth-step` | Plain labels, no links | Add links to existing EN intake heading IDs below; step 3/4 labels corrected as above |
|
||
| Six ES process cards | English-path `/aba-therapy-intake-process#first-step` through `#sixth-step`, with Spanish labels | Plain labels, no links | Add links to existing Spanish intake heading IDs below; labels unchanged |
|
||
| Learner journey video, both | `https://www.youtube-nocookie.com/embed/EczPH1jx9mc?si=beestOCaO4tL7Re6` | Same existing VideoCard destination | Retained; not played/fetched; privacy/loading behavior unchanged |
|
||
|
||
Intake destination mapping preserves section intent without editing the
|
||
out-of-scope intake records or copying nonexistent local HubSpot fragment IDs:
|
||
|
||
| Step / production fragment | EN local fragment on `/aba-therapy-intake-process` | ES local fragment on `/es/aba-therapy-intake-process` |
|
||
| --- | --- | --- |
|
||
| 1 / `first-step` | `1-complete-the-learner-information-form` | `1-complete-el-formulario-de-información-del-estudiante` |
|
||
| 2 / `second-step` | `2-speak-with-an-aia-client-advocate` | `2-hable-con-un-defensor-del-cliente-de-aia` |
|
||
| 3 / `third-step` | `3-fill-out-and-sign-the-client-intake-packet` | `3-complete-y-firme-el-paquete-de-admisión-del-cliente` |
|
||
| 4 / `fourth-step` | `4-verify-insurance-and-billing-information` | `4-verificar-la-información-del-seguro-y-la-facturación` |
|
||
| 5 / `fifth-step` | `5-schedule-your-childs-assessment` | `5-programa-la-evaluación-de-tu-hijo` |
|
||
| 6 / `sixth-step` | `6-collaborate-on-a-personalized-care-plan` | `6-colaborar-en-un-plan-de-atención-personalizado` |
|
||
|
||
No new route, redirect or form-activation behavior is introduced. Existing
|
||
consultation forms continue to state that online submission is not connected;
|
||
backend, privacy and workflow decisions remain separately gated.
|
||
|
||
### Human-decision and Multilingual Review Registers
|
||
|
||
| Classification / area | Supported observation | Uncertainty / action |
|
||
| --- | --- | --- |
|
||
| R + D — Insurance | Both homepages explicitly name BCBS AZ, Aetna, Optum, Tricare, **United Healthcare AHCCCS**, UnitedHealth; six logos match | Retain exact plan-specific wording. AIA billing must confirm products, networks, authorization/diagnosis/referral requirements and covered services; no inference that all AHCCCS or all insurer products are accepted. Carries forward Phase 5A's gate |
|
||
| R + D — ESA | Both sources give `$4,000 – $6,500` annually and say eligible families can apply funds to ABA tuition; ADE-vendor wording matches | Preserve existing qualified source wording, not a guarantee. Verify current award amounts, vendor status and eligible programs/expenses with AIA/ADE before public launch; no universal ESA eligibility inferred |
|
||
| P + D — HSA/FSA | EN source says AIA accepts account cards and funds may apply toward qualified care and ABA tuition/fees | Exact published copy/art retained. AIA billing/account administrators must verify card acceptance, eligible expenses and any additional qualifications; source alone does not establish reimbursement/tax eligibility. No independent financial advice or promise added |
|
||
| R + D — Financial assistance | Both sources describe assistance for the uninsured and paying over time | Eligibility, current availability and terms remain unverified. No financing product, universal approval, interest rate or new payment integration invented |
|
||
| R + D — Geography / availability | Existing Phoenix-area city list and in-center/in-home program commitments match retrieved sources | Current staffing, openings and service availability still need operational confirmation under Phase 5A's register; no new claims added |
|
||
| D — CTA/backend | Local EN/ES consultation and intake routes exist and resolve | Forms stay disabled. Backend, consent, privacy, callback/packet workflow and activation require separate authorization |
|
||
| D — Spanish language review | Hero removes `y adolescentes`; services heading inserts explicitly approved `18 meses a 8 años` | Human Spanish editor should review the two revised sentences in context. This is approved wording applied narrowly, not a fabricated translation or self-approved fluency |
|
||
| P + D — Spanish source differences | Spanish metadata/section wording differs; no HSA/FSA section; English testimonials and new logo alt text are published that way | Preserve differences. Human language/accessibility review may later localize source-supported alt text/quotes; no translations invented here |
|
||
| O — Detailed fidelity / unrelated content | HSA and logos get scoped responsive CSS; other component styling retained | Phase 8 full-page desktop/mobile comparison, spacing/crops/typography and any shared header/footer reconciliation remain outstanding; Library, services beyond 5A, employee portal and Ads work untouched |
|
||
|
||
There is **no unresolved human decision about general ABA ages or the removal
|
||
of the superseded audience wording**. Remaining questions above concern separate
|
||
financial, operational, language or integration facts.
|
||
|
||
### Validation and Reproduction
|
||
|
||
Run from `www/`:
|
||
|
||
```sh
|
||
npm run test:seo
|
||
npm run test:publication
|
||
npm run test:markdown
|
||
npm run build
|
||
PUBLIC_ALLOW_INDEXING=true npm run build
|
||
# Refresh local fingerprint using saved evidence, without any live crawl:
|
||
npm run audit:routes -- --offline --evidence reports/route-reconciliation-2026-10-09-offline.json
|
||
npm run audit:routes -- --check
|
||
npm run audit:links
|
||
npm run audit:images
|
||
npm run audit:blog
|
||
npm run build
|
||
# Preserve a separate reconciliation of the restored staging artifact:
|
||
npm run audit:routes -- --offline --evidence reports/route-reconciliation-2026-10-09-offline.json
|
||
npm run audit:routes -- --check
|
||
git diff --check
|
||
```
|
||
|
||
The tool creates a new timestamp-suffixed report rather than overwriting existing
|
||
evidence. This phase retains the final staging reconciliation as
|
||
[`route-reconciliation-2026-10-09-offline-03-57-29-199Z.json`](route-reconciliation-2026-10-09-offline-03-57-29-199Z.json).
|
||
The intermediate indexing reconciliation was moved to `/tmp` after its check.
|
||
All **70 inherited production requests**, observation timestamps, production
|
||
route records, original baseline and summary totals were preserved by deep
|
||
comparison. No new production crawl was used to refresh the fingerprint.
|
||
Only the local `/` route record changes title/description; generated route keys
|
||
are unchanged. Historical discovery still has 129 route keys and 102 source
|
||
sitemap URLs; those are not the current local 92-entry production-policy sitemap.
|
||
|
||
| Check | Result |
|
||
| --- | --- |
|
||
| `test:seo` | **30 passed**, including four new homepage tests and all earlier SEO/service cases |
|
||
| `test:publication` | **33 passed** |
|
||
| `test:markdown` | **20 passed** |
|
||
| Initial normal, indexing-enabled, final normal builds | All pass; each **96 routes**, Astro check **0 errors / 0 warnings / 0 hints** |
|
||
| `audit:routes -- --check` | Pass for indexing and restored staging evidence; offline, no network |
|
||
| `audit:links` | **0 broken internal links** |
|
||
| `audit:images` | **0 missing mapped page images**; focused test also checks every homepage `<img>` asset |
|
||
| `audit:blog` | **0 failures** |
|
||
| `git diff --check` | Pass |
|
||
| Browser | Unavailable: `Transport closed`; no browser-level visual/interactive verification claimed |
|
||
|
||
The first SEO run found two incorrect assumptions in the new tests: an Astro
|
||
script/style node intervenes after testimonials, and the process and commitment
|
||
CTAs share an assessment label. Assertions now check the next content element
|
||
and distinguish consultation links from process links. Rerun passed all 30 tests;
|
||
no application defect or relaxed route/eligibility requirement was involved.
|
||
|
||
Four focused tests cover valid/incomplete homepage schema input, present/absent
|
||
optional blocks, old unlinked steps, approved ABA ranges and absent superseded
|
||
audiences, retained 11 historical testimonials, source metadata, section order,
|
||
English-only HSA/FSA and its qualifications, final logo row, one H1, same-language
|
||
CTA routes and all 12 real intake IDs, disabled destination forms, local image
|
||
files and absence of financial JSON-LD. Optional blocks/links are removed only
|
||
inside the existing temporary fixture build to verify backward compatibility.
|
||
Existing tests exercise publication metadata in both modes without duplicating
|
||
its policy implementation.
|
||
|
||
| Generated-output invariant | Indexing-enabled, checked 03:56:49 UTC | Final staging, checked 03:57:28 UTC |
|
||
| --- | --- | --- |
|
||
| HTML routes | **96**, identical route set | **96**, identical route set |
|
||
| Sitemap URLs | **92** | **0** |
|
||
| Hreflang | **174 links / 53 pages** | **0 links** |
|
||
| Robots | Existing 92 indexable / four noindex exceptions | Every page **`noindex,nofollow`** |
|
||
| Canonicals, languages/directions, visible H1s | Unchanged across all routes | Unchanged across all routes |
|
||
| JSON-LD | Unchanged: 96 MedicalOrganization, 63 BlogPosting, 21 FAQPage | Same objects/counts |
|
||
|
||
All-route comparison against the starting staging artifact confirmed unchanged
|
||
header/footer/language-switcher destinations and unrelated main text; scripts
|
||
and styles are excluded from visible-text comparison (contact-obfuscation IDs
|
||
are randomized). Only `/` and `/es` change body copy. Only `/` changes title,
|
||
description and their existing social-metadata projections. No canonical,
|
||
indexing, translation, x-default, sitemap, display-H1, social-metadata or
|
||
structured-data policy implementation changed. `/ar` stays unpublished; all
|
||
four noindex/external-canonical exceptions remain excluded as before.
|
||
|
||
### Read-only Structural Diff Review and Complete File Inventory
|
||
|
||
**13 files: eight modified, five new.** Paths below are relative to `www/`.
|
||
|
||
| Classification | File | Reason |
|
||
| --- | --- | --- |
|
||
| English content | `src/content/pages/en/index.md` | Approved audience/range, source metadata/labels, HSA/FSA, intake links and logo data |
|
||
| Spanish content | `src/content/pages/es/index.md` | Two approved audience/range edits, existing-label Spanish intake links and source logo data; no HSA/FSA |
|
||
| Content model | `src/types/home-sections.ts` | Optional HSA/FSA and logo blocks plus optional process destinations; no Schema.org additions |
|
||
| Homepage composition | `src/components/pages/HomePage.astro` | Render optional sections in observed order, including legacy sections-array support |
|
||
| Homepage presentation | `src/components/home/HomeProcess.astro` | Link existing process-card content to validated local intake sections; preserve fallback and client script |
|
||
| Homepage presentation, **new** | `src/components/home/HomeHsaFsa.astro` | Source-oriented image/text layout with narrow responsive CSS |
|
||
| Homepage presentation, **new** | `src/components/home/HomeLogos.astro` | Optional source image row after testimonials, responsive and unlinked |
|
||
| Source asset, **new** | `public/assets/images/hsa-fsa-accepted.png` | Exact self-hosted published PNG; provenance/hash above |
|
||
| Regression tests | `tools/seo.test.mjs` | Four homepage tests within existing temporary Astro build suite; prior tests preserved |
|
||
| Editing documentation | `README.md` | New optional homepage fields and valid locale/fragment destinations |
|
||
| Milestone report | `reports/migration-summary.md` | This dated section; earlier history untouched |
|
||
| Source evidence, **new** | `reports/phase-5b-source-evidence-2026-10-09.json` | Cache-aware read-only observations, exact changes and verification |
|
||
| Offline audit, **new** | `reports/route-reconciliation-2026-10-09-offline-03-57-29-199Z.json` | Updated local fingerprint/metadata; inherited production evidence unchanged |
|
||
|
||
Reviewed scope excludes services/intake source records, Library, team, employee
|
||
portal, separate Ads landing pages, global navigation/footer, deployment,
|
||
dependencies/lockfile, Git configuration, form components/backends, analytics,
|
||
consent and payment integration. No new translation relationships or fabricated
|
||
Spanish sections were introduced. No staging, commit, push or Phase 5C work.
|
||
|
||
`merge-plan.md` remains untracked and unchanged, verified SHA-256:
|
||
`015db80cdbaf7d68799265d2070db760155c342b432ce6795f17ebc2218c641c`.
|
||
|
||
Tracked-file diff summary (`git diff --stat`; five new files are listed above
|
||
and are not included by Git until staged):
|
||
|
||
```text
|
||
www/README.md | 7 +
|
||
www/reports/migration-summary.md | 324 ++++++++++++++++++++++++++++++
|
||
www/src/components/home/HomeProcess.astro | 17 +-
|
||
www/src/components/pages/HomePage.astro | 8 +
|
||
www/src/content/pages/en/index.md | 37 +++-
|
||
www/src/content/pages/es/index.md | 18 +-
|
||
www/src/types/home-sections.ts | 14 ++
|
||
www/tools/seo.test.mjs | 114 +++++++++++
|
||
8 files changed, 526 insertions(+), 13 deletions(-)
|
||
```
|
||
|
||
## Phase 5C — Team Content Reconciliation (2026-10-09 UTC)
|
||
|
||
Phase 5C reconciles the English `/team` route with the roster and supporting
|
||
content currently presented by the public Team page. It does not infer hiring,
|
||
departure, promotion, employment status, or dates from differences between the
|
||
two sites. No Spanish Team record exists, and none was created.
|
||
|
||
### Sources, Retrieval, and Freshness
|
||
|
||
The source page was `https://www.azinstitute4autism.com/team`. `robots.txt` was
|
||
retrieved first at **2026-10-09 17:11:37 UTC** and allows `/` while disallowing
|
||
HubSpot preview and `hsCacheBuster` patterns. Two bounded, sequential Team-page
|
||
GETs were made at **17:11:39** and **17:11:40 UTC** using `Cache-Control:
|
||
no-cache, max-age=0` and `Pragma: no-cache`; the second used a unique audit query.
|
||
Both returned HTTP 200 and byte-identical bodies (SHA-256
|
||
`246f1afc7ebee26cf855f79fd82b3b734c717969bcd8e00361108d68af867adf`).
|
||
|
||
Both responses reported `x-hs-cf-cache-status: HIT`, `cache-control:
|
||
s-maxage=36000, max-age=5`, `x-hs-cache-control: s-maxage=36000, max-age=0`,
|
||
`Last-Modified: Sat, 03 Oct 2026 23:13:20 GMT`, and the same
|
||
`x-hs-prerendered` timestamp. Neither supplied `Age`, `ETag`, or
|
||
`CF-Cache-Status`. A separate current web rendering agreed on the ordered
|
||
roster, copy, links, and image assignments. The evidence is therefore
|
||
classified **potentially cached but consistently publicly presented**. No
|
||
contradictory public version was found; cache-bypass headers and the query are
|
||
not treated as proof of an origin-fresh response.
|
||
|
||
Ten roster/hero image requests and one social-image request were read-only and
|
||
sequential. No authentication, form submission, production API call, or write
|
||
occurred. Raw production HTML, cookies, and removed public entries are not
|
||
committed. Detailed headers, hashes, source strings, asset mappings, and
|
||
limitations are preserved in
|
||
[`phase-5c-source-evidence-2026-10-09.json`](phase-5c-source-evidence-2026-10-09.json).
|
||
|
||
Repository inspection covered `PageLayout.astro`, `PageHero.astro`,
|
||
`BaseLayout.astro`, `Seo.astro`, `TeamPage.astro`, `ContactObfuscation.astro`,
|
||
`Button.astro`, `content.config.ts`, `team.md`, `page-visuals.ts`, shared site
|
||
data, the publication manifest/policy, the route manifest, and the existing SEO
|
||
tests. The Phase 5A/5B reports, project instructions, migration brief, README,
|
||
and accepted migration history were also reviewed.
|
||
|
||
### Roster Reconciliation
|
||
|
||
Names, credentials, capitalization, roles, group order, member order, and image
|
||
assignments below reproduce the public presentation. “Removed” means only that
|
||
the entry is removed from the migrated public roster because the current
|
||
published page does not display it.
|
||
|
||
| Group / order | Previous rendered Astro roster | Public roster at 17:11 UTC | Resolution |
|
||
| --- | --- | --- | --- |
|
||
| 1. Board Certified Behavioral Analysts & Psychologists | Rula Diab, BCBA, LBA, M.Ed — Clinical Director; Jennifer Espinoza, MAOL/ABA — Clinical BCBA; Timirah Clay, M.Psy/ABA — Clinical BCBA | Rula Diab, BCBA, LBA, M.Ed — Clinical Director; Jennifer Espinoza, MAOL/ABA — Clinical BCBA | Retain first two in published order; remove Timirah Clay entry from migrated public roster |
|
||
| 2. Clinical Support | Carol Harrington, A.A. Spec. Ed. — Clinical Manager; Rachel Crosby — Clinical Administrator; Jennifer Bonefont, B.A. Psy — Clinical Client Advocate Supervisor | Jennifer Bonefont, B.A. Psy — Clinical Client Advocate Supervisor | Retain Jennifer Bonefont; remove Carol Harrington and Rachel Crosby entries from migrated public roster |
|
||
| 3. Clinical Case Supervisors | Rachael Sanchez, BS, M Psy/ABA — Clinical Supervisor | Same | Retain exactly |
|
||
| 4. Clinical Education Specialists | Mahima Bedi — Clinical Instructor | Same | Retain exactly |
|
||
| 5. ABA Clinic Management | Mariah Marley — Claims Billing; Eney Garcia, BA — Accounts Billing; Ayah Shahbander — Human Resources; Barbara Samanich, BFA — Creative Marketing Developer | Same names, credentials, roles, and order | Retain exactly; restore its missing parent heading and closing statement |
|
||
|
||
The page now renders **nine unique member cards**. No credentials were added or
|
||
normalized from outside sources, and no blog author record was changed.
|
||
|
||
### Photographs and Metadata
|
||
|
||
The hero and all nine rendered portraits are byte-for-byte matches to the
|
||
current source images. The hero is 1200×428; each portrait is 342×456. Existing
|
||
local filenames remain assigned to the same published person:
|
||
|
||
| Person / use | Local asset | Result |
|
||
| --- | --- | --- |
|
||
| Team hero | `hero-meet-the-aia-team.webp` | Existing exact match retained |
|
||
| Rula Diab | `team-rula-diab.webp` | Existing exact match retained |
|
||
| Jennifer Espinoza | `team-jennifer-espinoza.webp` | Existing exact match retained |
|
||
| Jennifer Bonefont | `team-jennifer-bonefont.webp` | Existing exact match retained |
|
||
| Rachael Sanchez | `team-rachael-sanchez.webp` | Existing exact match retained |
|
||
| Mahima Bedi | `team-mahima-bedi.webp` | Existing exact match retained |
|
||
| Mariah Marley | `team-mariah-marley.webp` | Existing exact match retained |
|
||
| Eney Garcia | `team-eney-garcia.webp` | Existing exact match retained |
|
||
| Ayah Shahbander | `team-ayah-shahbander.webp` | Existing exact match retained |
|
||
| Barbara Samanich | `team-barbara-samanich.webp` | Existing exact match retained |
|
||
|
||
Every card uses the pictured person's name as concise alt text and explicit
|
||
342×456 intrinsic dimensions. The three now-unreferenced historical portrait
|
||
files were not deleted; destructive asset cleanup is outside this milestone.
|
||
|
||
The title, description, canonical, H1, and `og:type=website` already matched and
|
||
remain unchanged. Production supplies `AIALanding_BG_V2.jpg` as the Team social
|
||
image with alt `learn more about arizona institute for autism`. An exact 2200×1146
|
||
JPEG copy is now self-hosted at `public/assets/images/AIALanding_BG_V2.jpg`
|
||
(SHA-256 `3036a9dc996b8ccd4672451fcc83b31b0421db4413f20d891f64f47d7707d6a8`)
|
||
and referenced through existing `featuredImage`/`alt` fields. It contains no
|
||
executable or unexpected embedded content by file-type inspection.
|
||
|
||
### Headings, Supporting Copy, Careers, and Contact
|
||
|
||
The intro heading, organization/location line, and paragraph already matched
|
||
production and were moved unchanged into the structured source. The component
|
||
now restores the published **Our ABA Care Team** section heading above **ABA
|
||
Clinic Management** and its closing statement, **ABA's leading experts in
|
||
special education and clinical care.** Repeated production module labels named
|
||
“Our Creative Team” are hidden by production CSS and were not presented as
|
||
visible headings or migrated.
|
||
|
||
Heading structure is now one page H1 from `PageHero`, H2s for major Team and
|
||
careers sections, H3s for roster groups, and H4s for member names. The existing
|
||
card appearance and responsive wrapping are retained; this is a semantic and
|
||
content correction rather than a Phase 8 visual redesign.
|
||
|
||
Production labels the careers CTA **View Open Positions** and links to
|
||
`/careers?hsLang=en`. Astro retains the equivalent safe local `/careers` route;
|
||
the route exists and the link audit passes. No recruiting form or integration
|
||
was activated.
|
||
|
||
Production has an internal HR-email inconsistency: the no-script fallback says
|
||
`hr [at] abaclinicaz [dot] com`, while its executable script makes both the
|
||
visible text and `mailto:` destination `hr@azinstitute4autism.com`. Astro
|
||
retains that active destination and now derives its obfuscated fallback from
|
||
the same value: `hr [at] azinstitute4autism [dot] com`. Regression coverage
|
||
decodes `ContactObfuscation` data and proves displayed/underlying values agree.
|
||
The shared public phone, info email, and Scottsdale address match production
|
||
and were not changed.
|
||
|
||
### Content Architecture Decision
|
||
|
||
Before this phase, `TeamPage.astro` hardcoded the rendered roster while
|
||
`team.md` contained a separate extracted roster that `PageLayout.astro` bypassed.
|
||
The two sources could drift without any validation. The smallest durable fix is
|
||
a validated `team:` object in the existing English Team record:
|
||
|
||
- `team-page.ts` defines required intro, groups, members, careers/contact, local
|
||
CTA, and nonempty strings, and rejects duplicate member names.
|
||
- `content.config.ts` exposes that optional page field through the existing Zod
|
||
content collection.
|
||
- `PageLayout.astro` requires the object for the dedicated English Team route
|
||
and passes it to `TeamPage.astro`.
|
||
- `TeamPage.astro` is presentation-only and maps the structured data into the
|
||
existing cards and sections.
|
||
- the bypassed Markdown body contains only a maintenance comment; it no longer
|
||
presents a competing roster.
|
||
|
||
This keeps the route and metadata in the established Front Matter CMS-compatible
|
||
record without a general component refactor. Future editors maintain one roster.
|
||
No Spanish record or translation relationship was manufactured.
|
||
|
||
### Human-decision Register and Deliberate Deferrals
|
||
|
||
| Topic | Evidence / resolution | Remaining action |
|
||
| --- | --- | --- |
|
||
| Source freshness | Direct recheck and independent current rendering agree; both direct bodies are an October 3 HubSpot cache HIT | Confirm roster operationally before launch if the cache date is material; no conflicting entry was guessed |
|
||
| Credentials and group membership | Reproduced verbatim from the current public page | AIA remains responsible for factual credential/role review; no outside directory was used |
|
||
| HR contact | Active production script consistently uses `hr@azinstitute4autism.com`; stale fallback uses another domain | Current active value is implemented. AIA may confirm the legacy fallback domain can be retired before launch |
|
||
| Unused portraits | Three prior entries are absent from current public presentation | Files remain unreferenced; later asset cleanup may remove them after a repository-wide usage review |
|
||
| Visual fidelity | Static HTML, CSS, dimensions, semantic structure, links, and assets validated | Full desktop/mobile comparison, crops, spacing, keyboard interaction, and hover fidelity remain Phase 8 work |
|
||
|
||
There are no unresolved image assignments in the implemented nine-member
|
||
roster. No roster difference is characterized as a personnel event.
|
||
|
||
### Validation and Generated-output Invariants
|
||
|
||
Run from `www/`:
|
||
|
||
```sh
|
||
npm run test:seo
|
||
npm run test:publication
|
||
npm run test:markdown
|
||
npm run build
|
||
PUBLIC_ALLOW_INDEXING=true npm run build
|
||
npm run audit:routes -- --offline --evidence reports/route-reconciliation-2026-10-09-offline-03-57-29-199Z.json
|
||
npm run audit:routes -- --check
|
||
npm run audit:links
|
||
npm run audit:images
|
||
npm run audit:blog
|
||
npm run build
|
||
npm run audit:routes -- --offline --evidence reports/route-reconciliation-2026-10-09-offline-03-57-29-199Z.json
|
||
npm run audit:routes -- --check
|
||
git diff --check
|
||
```
|
||
|
||
The final offline reconciliation is
|
||
[`route-reconciliation-2026-10-09-offline-17-20-21-008Z.json`](route-reconciliation-2026-10-09-offline-17-20-21-008Z.json).
|
||
It reuses all **70** saved production observations and makes no production
|
||
requests. Historical discovery remains 129 normalized routes and 102 source
|
||
sitemap URLs. The local generated count stays 96; the production-policy overlap
|
||
stays 92. An intermediate indexing-mode reconciliation was moved to `/tmp`.
|
||
|
||
| Check | Result |
|
||
| --- | --- |
|
||
| `test:seo` | **34 passed**, including four Phase 5C Team tests |
|
||
| `test:publication` | **33 passed** |
|
||
| `test:markdown` | **20 passed** |
|
||
| Initial normal, indexing-enabled, final normal builds | All passed; each generated **96 routes**; Astro check **0 errors / 0 warnings / 0 hints** |
|
||
| `audit:routes -- --check` | Passed in indexing and final staging modes using offline evidence |
|
||
| `audit:links` | **0 broken internal links** |
|
||
| `audit:images` | **0 missing mapped page images** |
|
||
| `audit:blog` | **0 failures** |
|
||
| `git diff --check` | Passed |
|
||
| Browser validation | Attempted, but Playwright returned `Transport closed`; no browser-level desktop/mobile claim is made |
|
||
|
||
The four focused Team tests validate the structured source and reject duplicate
|
||
names, blank text, and external careers destinations; validate every group,
|
||
member, role, order, local image, WebP signature, intrinsic dimensions, and alt;
|
||
validate one H1, heading hierarchy, restored copy, careers CTA, and decoded
|
||
contact agreement; and preserve title, description, canonical, robots, social
|
||
image, language/direction, hreflang behavior, and absence of `/es/team` in both
|
||
build modes.
|
||
|
||
| Generated-output invariant | Indexing-enabled | Final staging |
|
||
| --- | --- | --- |
|
||
| HTML routes | **96**, route set unchanged | **96**, route set unchanged |
|
||
| Sitemap URLs | **92** | **0**, empty XML urlset |
|
||
| Hreflang | **174 links across 53 pages** | **0 links** |
|
||
| Robots | Existing publication policy; Team `index,follow` | Every route `noindex,nofollow` |
|
||
| Team canonical | `https://www.azinstitute4autism.com/team` | Same |
|
||
| Team language/direction | `en` / `ltr` | Same |
|
||
| Team H1 | Exactly one | Exactly one |
|
||
|
||
No route, canonical, robots, sitemap, translation, hreflang, display-H1,
|
||
BlogPosting, FAQPage, organization-schema, analytics, form, advertising, or
|
||
deployment policy implementation changed. The only new metadata projection is
|
||
the source-supported Team social image through Phase 4A's existing machinery.
|
||
|
||
### Read-only Structural Diff Review and File Inventory
|
||
|
||
Phase 5C has **11 files: seven modified and four new**, all under `www/`:
|
||
|
||
| Classification | File | Purpose |
|
||
| --- | --- | --- |
|
||
| Editing documentation | `README.md` | Documents the single structured Team source |
|
||
| Presentation | `src/components/pages/TeamPage.astro` | Renders validated roster/copy, semantic hierarchy, matching contact, and existing card styles |
|
||
| Content schema | `src/content.config.ts` | Registers optional Team page data in the existing page schema |
|
||
| Content metadata/data | `src/content/pages/en/team.md` | Current nine-member roster, supporting copy, careers data, and social image; removes competing body roster |
|
||
| Route presentation | `src/layouts/PageLayout.astro` | Requires and passes Team data only for the established English Team route |
|
||
| Regression tests | `tools/seo.test.mjs` | Four focused generated-output/schema tests in the existing suite |
|
||
| Milestone documentation | `reports/migration-summary.md` | This dated review; prior evidence retained |
|
||
| Content schema, **new** | `src/types/team-page.ts` | Zod model and duplicate-member validation |
|
||
| Source asset, **new** | `public/assets/images/AIALanding_BG_V2.jpg` | Exact published Team social image |
|
||
| Source evidence, **new** | `reports/phase-5c-source-evidence-2026-10-09.json` | Cache-aware observations, roster, assets, corrections, and validation |
|
||
| Offline audit, **new** | `reports/route-reconciliation-2026-10-09-offline-17-20-21-008Z.json` | Updated local fingerprint with inherited production evidence |
|
||
|
||
Scope review found no homepage, service, consultation, Library, author,
|
||
employee-portal, Ads, navigation/footer, dependency/lockfile, deployment,
|
||
analytics, tracking, form/backend, or future-phase changes. No file is staged.
|
||
|
||
`merge-plan.md` remains untracked and unchanged. Its verified SHA-256 is
|
||
`015db80cdbaf7d68799265d2070db760155c342b432ce6795f17ebc2218c641c`.
|
||
|
||
## Phase 6A — Library Architecture Decision (2026-10-09 UTC)
|
||
|
||
**Starting checkpoint:** `34d5394b3ce765028a27b9cddd9952de3f09bfe7`.
|
||
This is a research and decision milestone. It changes no Library implementation,
|
||
content, dependency, route, redirect, publication rule, or deployment file.
|
||
|
||
### Scope and Method
|
||
|
||
Inspected the catchall route, all three Library index components,
|
||
`BlogIndexLayout`, `BlogCard`, `BlogPostLayout`, content/author schemas, all blog
|
||
and author records, publication policy/manifest, structured-data author
|
||
resolution, SEO/publication tests, route-audit tooling, Library page records,
|
||
README, migration instructions, accepted reports, and the latest offline route
|
||
reconciliation.
|
||
|
||
Production `robots.txt` was checked before 29 bounded sequential GETs from
|
||
**2026-10-09 18:01:51–18:02:17 UTC**. Requests covered Library/author roots,
|
||
first-page aliases, representative/last/invalid pages in all three languages,
|
||
trailing-slash examples, `/search`, and one search query. No redirects were
|
||
followed, forms submitted, authentication used, or production writes made. One
|
||
headless Chromium GET verified client-rendered search results.
|
||
|
||
Responses variously reported HubSpot `HIT`, `MISS`, or `REVALIDATED` and mostly
|
||
October 3–4 prerenders. They establish consistent current public behavior, not
|
||
origin freshness. Historical October 7 observations remain intact and support
|
||
the intervening English page 3–5/author page 3–5 statuses without repeat calls.
|
||
|
||
### Current Inventory and Confirmed Behavior
|
||
|
||
- **65 blog records:** 46 English, 12 Spanish, seven Arabic.
|
||
- All 65 are non-draft and generated. Two English syndicated records are
|
||
accessible `noindex` external-canonical exceptions, leaving **63 sitemap-
|
||
eligible posts**.
|
||
- Every post has title, description, date, author, category, featured image,
|
||
canonical, and translation key. Tags are empty on all 65; no post declares
|
||
`updatedDate` or image-alt frontmatter.
|
||
- Every post uses author slug `rula-diab`. There is one author record per
|
||
language, all sharing explicit translation key `rula-diab`.
|
||
- Current indexes sort date descending only; stable manifest order implicitly
|
||
breaks equal dates by route. They render every locale post in one list.
|
||
- English alone has an inert search input. Spanish/Arabic have no search control.
|
||
No local pagination or author routes exist.
|
||
- The three Library Markdown bodies contain bypassed historical listing
|
||
snapshots, creating a stale competing representation even though they do not
|
||
render.
|
||
- Production uses ten posts per page: English 55 posts/six pages, Spanish 12/two,
|
||
Arabic seven/one. Author archives have the same counts because all posts are
|
||
currently attributed to Rula Diab.
|
||
- All six `/page/1` Library/author aliases return duplicate 200 content. English
|
||
trailing-slash examples return 301 to no-slash roots. First invalid page
|
||
boundaries return 404.
|
||
- Production search is a JavaScript-rendered GET `/search` flow. A browser query
|
||
for `autism` returned 66 mixed-language blog/listing results, ten per offset
|
||
page. Raw HTML contains no results and production supplies no useful search
|
||
canonical/robots/title.
|
||
|
||
### Architecture Recommendation
|
||
|
||
Generate one small metadata-only JSON search index per language from a new
|
||
shared Library catalog based on the existing publication manifest. Use a
|
||
dependency-free TypeScript client with Unicode-aware English/Spanish/Arabic
|
||
normalization, weighted deterministic matching, accessible result state, and no
|
||
external query service. Current measured aggregate metadata is 42,090 bytes raw,
|
||
12,693 gzip, or 10,709 Brotli; a raw-body prototype is 474,623/135,796 gzip and
|
||
is not recommended without a verified need.
|
||
|
||
Use the same catalog for ten-item static Library and author pagination, explicit
|
||
date-descending/route-ascending sorting, author validation, and generated route
|
||
descriptors integrated with the shared publication policy. Page 1 remains each
|
||
root; `/page/1` becomes a locale-specific permanent redirect. Invalid or empty
|
||
pages are not generated. Numbered pages never gain hreflang from matching page
|
||
numbers. Author roots may use explicit author translation keys after localized
|
||
author content is source-reconciled and reviewed.
|
||
|
||
The complete proposal, alternatives, current evidence, URL disposition matrix,
|
||
route-count model, multilingual/RTL/SEO design, accessibility behavior, Phase 6B
|
||
checkpoints, test matrix, and decision register are in
|
||
[`phase-6a-library-architecture.md`](phase-6a-library-architecture.md).
|
||
|
||
### Route Implications and Sequencing
|
||
|
||
With the current corpus, the proposed `/search`, five numbered Library pages,
|
||
three author roots, and five numbered author pages would add 14 HTML routes:
|
||
**96 → 110**. Under the recommended policy, sitemap URLs would be **92 → 105**.
|
||
Validated author-root equivalence would add 12 hreflang links: **174 → 186**.
|
||
Redirect aliases add no HTML routes.
|
||
|
||
The current corpus can generate only five nonempty English pages. Production
|
||
page 6 and author page 6 contain real distinct content. Phase 6C's nine missing
|
||
English posts must therefore precede final pagination acceptance; no empty page,
|
||
generic-home redirect, or fabricated record is recommended. If all nine are
|
||
ordinary indexable records, the combined upper-bound projection is 121 HTML
|
||
routes and 116 sitemap URLs; exact policy and translation relationships must be
|
||
recomputed from the reconciled records.
|
||
|
||
### Validation
|
||
|
||
| Check | Result |
|
||
| --- | --- |
|
||
| Normal `npm run build` | Passed; Astro check 0 errors/warnings/hints; 96 HTML routes |
|
||
| `npm run audit:routes -- --check` | Passed offline against `route-reconciliation-2026-10-09-offline-17-20-21-008Z.json`; no network/writes |
|
||
| Indexing-enabled evidence build | Passed; 96 routes, 92 sitemap URLs, 174 hreflang links across 53 pages |
|
||
| Final normal build | Passed; restored staging output |
|
||
| Final staging safeguards | 96 routes; global `noindex,nofollow`; empty sitemap; no hreflang |
|
||
|
||
### Decisions Awaiting Approval
|
||
|
||
1. Metadata-only dependency-free search rather than full-body/Pagefind/client
|
||
library search.
|
||
2. Ten posts per page and permanent page-1 alias redirects.
|
||
3. Preserved noindex `/search` compatibility for `term`, `q`, legacy `type`, and
|
||
`offset`, while embedded Library search remains locale-scoped.
|
||
4. Indexable, self-canonical, sitemap-listed numbered/archive pages.
|
||
5. Continued listing/search visibility for the two accessible noindex syndicated
|
||
pages, preserving current Astro behavior.
|
||
6. Explicit author-root hreflang, optional localized author `displayName`, and
|
||
source-supported author bio reconciliation with human language review.
|
||
7. Phase 6C content sequencing before English page-6 acceptance.
|
||
|
||
No functional source file, dependency, route, redirect rule, content record,
|
||
Nix/nginx/deployment configuration, publication policy, or generated application
|
||
behavior was changed in Phase 6A.
|
||
|
||
## Phase 6A Architecture Ratification — October 9, 2026
|
||
|
||
The Phase 6A proposal was ratified against checkpoint
|
||
`76a035424dc5245443476b168d8c91ea62eed27b` with the following decisions. The
|
||
original proposal remains preserved as historical architecture research;
|
||
these later decisions govern Phase 6B implementation.
|
||
|
||
1. **Search architecture approved.** Library search uses the existing content
|
||
collections and publication manifest, locale-specific static JSON indexes,
|
||
and dependency-free project-owned TypeScript. Initial fields are title,
|
||
description, headings, category, author display information, publication
|
||
date, and future nonempty tags. Full-body indexing, fuzzy matching,
|
||
stemming, hosted services, query logging, and third-party dependencies remain
|
||
deferred or disallowed.
|
||
2. **Library pagination approved for a later checkpoint.** The agreed model is
|
||
ten posts per page, publication date descending, normalized route ascending
|
||
as a stable tie-breaker, the unnumbered root as page 1, nonempty generated
|
||
pages 2+, and HTTP 301 redirects from `/page/1` aliases. Phase 6B.1 does not
|
||
implement this decision.
|
||
3. **Legacy `/search` approved with a narrower initial scope.** It preserves
|
||
`term`, `q`, repeated `type`, and `offset` compatibility but searches only
|
||
Library articles. It is `noindex`, sitemap-excluded, and outside the
|
||
hreflang graph. This intentional Library-only behavior differs from
|
||
HubSpot's broader production site search.
|
||
4. **Archive indexing policy modified.** Future numbered Library pages are
|
||
self-canonical, indexable, and sitemap-eligible. Future author roots and
|
||
numbered author pages are initially `noindex,follow` and omitted from the
|
||
sitemap. This replaces the proposal's recommendation to index all archive
|
||
pages immediately. Phase 6B.1 creates no author routes.
|
||
5. **Syndicated-article handling approved.** The two accessible English records
|
||
`community-highlight-meet-rula-diab` and `new-aia-scottsdale-office` remain
|
||
available in Library listings and internal search while retaining their
|
||
external canonicals, `noindex`, sitemap exclusion, and hreflang exclusion.
|
||
6. **Author-root hreflang conditionally approved for later work.** It requires
|
||
explicit validated author translation keys plus eligible, indexable author
|
||
roots. Numbered author pages never receive hreflang merely from matching page
|
||
numbers. Because author archives initially remain `noindex`, Phase 6B.1 adds
|
||
no author hreflang.
|
||
7. **Author content model approved for later work.** An optional localized
|
||
`displayName` may reproduce source-supported archive headings, while the
|
||
person's actual name remains the BlogPosting Person attribution. Biography
|
||
reconciliation and substantive Spanish/Arabic edits require source evidence
|
||
and human language review. Phase 6B.1 uses the existing author schema.
|
||
8. **Phase 6C sequencing approved with a cutover constraint.** Pagination may
|
||
precede reconciliation of the nine missing English articles, but no records
|
||
or empty pages may be fabricated. Production `/library/page/6` and
|
||
`/library/author/rula-diab/page/6` cannot be accepted as migrated until
|
||
Phase 6C supplies the necessary source-supported content.
|
||
|
||
The ratification therefore modifies four material recommendations in the
|
||
original proposal: `/search` initially searches Library content rather than the
|
||
whole site; author archives begin as `noindex` and outside the sitemap;
|
||
author-root hreflang waits for later content and indexing approval; and Library
|
||
pagination may be implemented before Phase 6C even though production page-6
|
||
acceptance may not. Only the search-related parts of Decisions 1, 3, and 5 were
|
||
authorized for Phase 6B.1. Pagination, author archives, redirects, and Phase 6C
|
||
content retain separate review gates.
|
||
|
||
## Phase 6B.1 — Shared Library Catalog and Search — October 9, 2026
|
||
|
||
**Starting checkpoint:** `76a035424dc5245443476b168d8c91ea62eed27b`
|
||
|
||
### Scope and Architecture
|
||
|
||
Phase 6B.1 implements one shared Library catalog, three generated static search
|
||
indexes, progressively enhanced locale-scoped search on the three Library
|
||
roots, and a static `/search` compatibility page. It adds no pagination or
|
||
author archive routes, changes no article body or date, installs no dependency,
|
||
and sends no query to an external service.
|
||
|
||
`src/utils/library-catalog.ts` is the single reusable catalog layer. It consumes
|
||
generated blog entries from the Phase 3A publication manifest, resolves authors
|
||
from the existing localized author records, and returns immutable metadata
|
||
records separated by locale. It includes route-eligible accessible records even
|
||
when they are `noindex` or externally canonicalized, while excluding drafts and
|
||
other non-generated records. Results sort by publication date descending and
|
||
normalized local route ascending; duplicate routes, missing authors, and
|
||
ambiguous authors fail explicitly. That ordering and data shape can be reused by
|
||
the later approved pagination work without maintaining a second article list.
|
||
|
||
The catalog extracts bounded Markdown/MDX headings while ignoring fenced code,
|
||
component syntax, and non-heading body content. A record contains only:
|
||
|
||
- stable local URL and locale;
|
||
- title and description;
|
||
- at most 50 meaningful headings, each capped at 300 characters;
|
||
- category and future nonempty tags;
|
||
- localized author name and slug; and
|
||
- publication date.
|
||
|
||
It does not serialize article bodies, rendered HTML, canonicals, form data,
|
||
visitor data, analytics identifiers, credentials, cookies, draft metadata, or
|
||
runtime secrets. `src/utils/library.ts` adapts the pure catalog to Astro content
|
||
collections and memoizes it for a build. The JSON endpoint at
|
||
`src/pages/assets/search/library/[locale].json.ts` creates deterministic UTF-8
|
||
assets for `en`, `es`, and `ar` on every build.
|
||
|
||
### Search Normalization and Ranking
|
||
|
||
`src/utils/library-search.ts` owns DOM-independent matching and compatibility
|
||
query parsing. It applies Unicode NFKC normalization, locale-aware lowercasing,
|
||
collapsed whitespace, punctuation normalization, Spanish accent-insensitive
|
||
matching, and removal of Arabic combining marks and tatweel while preserving
|
||
original display text. It does not stem or fuzzily rewrite words. Documented
|
||
partial-token matching begins at three characters to accommodate useful prefix
|
||
and attached-particle matches without turning short tokens into broad matches.
|
||
|
||
All normalized query terms must match. Deterministic weights favor an exact
|
||
title phrase, then title tokens, headings, description, category/tags, and
|
||
author metadata. Equal scores sort by publication date descending and route
|
||
ascending. Empty or whitespace-only input restores ordinary browsing. Unusual
|
||
punctuation and Unicode input, no matches, one match, multiple matches, and
|
||
cleared queries are covered by the focused test suite.
|
||
|
||
### Embedded Library Search
|
||
|
||
`LibrarySearch.astro` supplies the shared accessible interface for `/library`,
|
||
`/es/library`, and `/ar/library`. Each root loads only its own locale index on
|
||
the first real search. The existing server-rendered list remains complete (46
|
||
English, 12 Spanish, seven Arabic) because ten-item pagination is deferred.
|
||
Search state uses a `#search=` fragment, supports direct links and browser
|
||
back/forward navigation, and avoids sending embedded queries to a static server.
|
||
Clearing a query restores the server-rendered list and its pre-search fragment.
|
||
|
||
Controls become visible only after successful client initialization. The
|
||
ordinary listing and links remain available without JavaScript; a `<noscript>`
|
||
message describes the limitation. A failed index request reports the error but
|
||
does not hide or blank the archive. The component uses a visible label, native
|
||
search input, submit and reset controls, visible focus styles, result heading,
|
||
and a polite live region. It moves focus predictably after submission/reset,
|
||
does not trap focus, and creates all query/result text with DOM `textContent`
|
||
rather than unsanitized HTML.
|
||
|
||
English, Spanish, and Arabic use locale-scoped indexes and existing route
|
||
conventions. Arabic retains `lang="ar"`, `dir="rtl"`, RTL input/result
|
||
presentation, and logical DOM focus order. The source-supported control labels
|
||
`Search`, `Buscar`, and `بحث` are retained. Newly introduced Spanish and Arabic
|
||
operational microcopy (loading, errors, counts, reset, and no-results text) is
|
||
functionally complete but requires human language review; it is not represented
|
||
as professionally reviewed translation.
|
||
|
||
### Legacy `/search` Compatibility
|
||
|
||
The generated `/search` page states that it searches AIA Library articles,
|
||
rather than promising HubSpot's global-page search. `term` has precedence over
|
||
`q` when both are present; repeated legacy `type` values are accepted as
|
||
compatibility inputs but do not broaden the corpus. Visitors may search all
|
||
three indexes or explicitly filter by English, Spanish, or Arabic. A narrow
|
||
filter fetches only the selected index. Results use ten-item offset pages;
|
||
nonnegative multiples of ten are accepted, and invalid, negative,
|
||
non-numeric, non-multiple, or beyond-range offsets normalize to a valid state
|
||
without exposing nonexistent records.
|
||
|
||
The page is static, self-canonical to
|
||
`https://www.azinstitute4autism.com/search`, `noindex,follow` in an
|
||
indexing-enabled build, excluded from the sitemap, and excluded from hreflang.
|
||
The final staging build applies the global `noindex,nofollow` safeguard. Its
|
||
no-JavaScript fallback explains the requirement and links to all three working
|
||
Library roots. Query-string values can appear in ordinary server logs, unlike
|
||
fragment-based embedded queries; the page documents that privacy distinction.
|
||
No cookies, local search history, analytics, query logging, external API,
|
||
HubSpot forwarding, or persistent backend was added.
|
||
|
||
The route is integrated through the existing publication-policy API using the
|
||
small synthetic descriptor in `search-publication.ts`; it does not introduce a
|
||
second robots/canonical/sitemap policy. The publication manifest and sitemap
|
||
continue to represent content-backed routes only. The existing two syndicated
|
||
articles remain accessible in listings and search while their external
|
||
canonicals, `noindex`, sitemap exclusion, and hreflang exclusion remain intact.
|
||
|
||
### Generated Asset Measurements
|
||
|
||
Measurements were taken from the final generated JSON assets using local gzip
|
||
and Brotli compression:
|
||
|
||
| Locale | Records | Raw bytes | Gzip bytes | Brotli bytes |
|
||
| --- | ---: | ---: | ---: | ---: |
|
||
| English | 46 | 28,003 | 7,973 | 6,632 |
|
||
| Spanish | 12 | 10,170 | 3,427 | 2,969 |
|
||
| Arabic | 7 | 6,234 | 1,982 | 1,625 |
|
||
| **Total** | **65** | **44,407** | **13,382** | **11,226** |
|
||
|
||
The total is 2,317 raw bytes and 689 gzip bytes above Phase 6A's prototype,
|
||
primarily because the implemented records carry validated author objects,
|
||
bounded extracted headings, and their final endpoint representation. It remains
|
||
a metadata-only index. The final shared client module is 6,539 bytes raw, 2,651
|
||
bytes with gzip, and 2,312 bytes with Brotli. Measurements use `gzip -9 -n` and
|
||
`brotli -q 11`. Ordinary Library visits fetch no index until a search starts,
|
||
embedded searches fetch one locale, and filtered legacy searches avoid unused
|
||
locale assets. All query processing occurs in the browser.
|
||
|
||
### Validation and Browser Evidence
|
||
|
||
| Check | Result |
|
||
| --- | --- |
|
||
| `npm run test:library` | Passed: 16 tests covering real catalogs/build output, publication exclusions, syndicated inclusion, authors, sorting, headings, Unicode matching, legacy state, SEO, and safe client rendering |
|
||
| `npm run test:seo` | Passed: 34 tests |
|
||
| `npm run test:publication` | Passed: 33 tests |
|
||
| `npm run test:markdown` | Passed: 20 tests |
|
||
| Normal `npm run build` | Passed: Astro check reported 0 errors, warnings, or hints; 97 HTML routes |
|
||
| `PUBLIC_ALLOW_INDEXING=true npm run build` | Passed: 97 HTML routes, 92 sitemap URLs, 174 hreflang links across 53 pages |
|
||
| `npm run audit:routes -- --check` | Passed after the normal offline reconciliation process recorded the intentional `/search` route; no new production crawl |
|
||
| `npm run audit:links` | Passed: 0 broken internal links |
|
||
| `npm run audit:images` | Passed: 0 missing images |
|
||
| `npm run audit:blog` | Passed: 0 failures |
|
||
| Final normal `npm run build` | Passed and restored staging output: all 97 pages `noindex,nofollow`, empty sitemap, no hreflang |
|
||
| `git diff --check` | Passed |
|
||
|
||
The preserved-production offline reconciliation is
|
||
`route-reconciliation-2026-10-09-offline-20-22-09-196Z.json`: 129 reconciled
|
||
routes, 97 locally generated routes, and 70 inherited production verification
|
||
requests. It preserves the earlier observations rather than asserting a new
|
||
production crawl.
|
||
|
||
Chromium DevTools Protocol checks exercised the generated static site at desktop
|
||
and a 390-by-844 mobile Arabic viewport. They confirmed that an ordinary Library
|
||
visit loads no JSON; direct fragments and Enter submission work; reset and
|
||
back/forward restore state; failed JSON loading leaves 46 English cards usable;
|
||
JavaScript-disabled English retains all 46 cards and working links; the legacy
|
||
page honors `term` precedence and ten-result offsets; a Spanish filter fetches
|
||
only the Spanish index; and Arabic results/input remain RTL without horizontal
|
||
overflow. These checks also observed correct focus movement and live status
|
||
updates. No screenshots or browser artifacts were added to the repository.
|
||
|
||
The user also completed the full manual browser acceptance checklist against the
|
||
built static site served through the project's nginx/reverse-proxy environment
|
||
at `https://aia.web3app.dev`; every checklist item passed. Results display the
|
||
clear heading “Library Search Results,” keyboard submission moves focus to that
|
||
results region, the next Tab reaches the first result, and the browser focus
|
||
indicator remains visible. That intentional results-region focus behavior was
|
||
accepted without an additional accessibility correction. This acceptance did
|
||
not claim testing with a specific screen reader, and a separate Astro preview
|
||
run was unnecessary because the built output had already been tested through
|
||
the existing static-serving environment.
|
||
|
||
### Publication, Route, and Scope Invariants
|
||
|
||
- Generated HTML routes changed only from 96 to **97** for `/search`.
|
||
- The indexing-enabled sitemap remains **92** URLs.
|
||
- Indexing-enabled hreflang remains **174** links across **53** routes.
|
||
- `/search` is self-canonical, `noindex,follow`, sitemap-excluded, and has no
|
||
hreflang in the indexing-enabled build.
|
||
- Final staging output contains **97** globally `noindex,nofollow` pages, an
|
||
empty sitemap, and no hreflang.
|
||
- The three generated JSON assets are static assets, not HTML routes.
|
||
- No new article, numbered Library, author, or translation route exists.
|
||
- Canonicals, existing Library-root translation relationships, publication
|
||
eligibility, syndicated exceptions, BlogPosting/FAQPage rules, author
|
||
attribution, Header, Footer, LanguageSwitcher, forms, and integrations are
|
||
unchanged.
|
||
|
||
Phase 6B.1 deliberately did not implement Library pagination, `/page/1`
|
||
redirects, author archives, author schema/biography changes, article/date
|
||
reconciliation, production redirects, Phase 6C records, hosting configuration,
|
||
analytics, or an external search service.
|
||
|
||
### Changed-File Inventory
|
||
|
||
Modified files:
|
||
|
||
- `package.json` — adds the focused `test:library` command.
|
||
- `src/components/pages/LibraryEnglish.astro`
|
||
- `src/components/pages/LibrarySpanish.astro`
|
||
- `src/components/pages/LibraryArabic.astro` — consume the shared catalog and
|
||
mount the reusable search enhancement while retaining complete SSR listings.
|
||
- `src/layouts/BlogIndexLayout.astro` — narrowly scoped search/result styling.
|
||
- `src/utils/publication-policy.ts` — broadens the existing descriptor's data
|
||
type for fields already consumed by the catalog; policy behavior is unchanged.
|
||
- `src/utils/publication.ts` — resolves the `/search` utility descriptor through
|
||
the existing publication API.
|
||
- `tools/publication.test.mjs` and `tools/seo.test.mjs` — include the deliberate
|
||
`/search` route in route and SEO invariants.
|
||
- `reports/migration-summary.md` — records ratification, implementation, and
|
||
validation evidence.
|
||
|
||
New files:
|
||
|
||
- `src/utils/library-catalog.ts`
|
||
- `src/utils/library-search.ts`
|
||
- `src/utils/library.ts`
|
||
- `src/utils/search-publication.ts`
|
||
- `src/components/LibrarySearch.astro`
|
||
- `src/pages/assets/search/library/[locale].json.ts`
|
||
- `src/pages/search.astro`
|
||
- `tools/library.test.mjs`
|
||
- `reports/route-reconciliation-2026-10-09-offline-20-22-09-196Z.json`
|
||
|
||
### Remaining Review Items
|
||
|
||
1. Human language review is required for the newly introduced Spanish and
|
||
Arabic search-state/accessibility microcopy. This does not change or invent
|
||
article translations.
|
||
2. The intentional Library-only scope of `/search` should remain visible to
|
||
stakeholders because it differs from production HubSpot global search.
|
||
3. Pagination, page-1 redirect rules, noindex author archives, eventual author
|
||
indexability/hreflang, author biographies, and Phase 6C page-6 content remain
|
||
separate approved or conditional checkpoints and are not implemented here.
|
||
|
||
## Phase 6B.2 — Library Pagination and Page-1 Redirects (2026-10-10)
|
||
|
||
### Scope and Starting State
|
||
|
||
Phase 6B.2 started from checkpoint
|
||
`b20c253383440598c2d07bf6f852906ac00c42df` on
|
||
`faithful-astro-migration`. It implements deterministic, static pagination for
|
||
the three existing Library roots and repository-level redirect definitions for
|
||
their first-page aliases. It does not add Library articles, author routes,
|
||
author metadata, production hosting configuration, or deployment changes.
|
||
|
||
The Phase 6B.1 catalog was recalculated from the repository rather than from
|
||
historical counts. It contains 46 eligible English records, 12 Spanish records,
|
||
and seven Arabic records. The two accessible English syndicated records remain
|
||
in that listing catalog despite retaining their external canonicals and
|
||
`noindex` publication treatment.
|
||
|
||
### Shared Pagination and Route Integration
|
||
|
||
`src/utils/library-pagination.ts` is a pure, reusable layer over the existing
|
||
catalog. Its page size is ten. It reports total items, nonempty page count,
|
||
current slice, and previous/next page numbers; rejects unsafe, non-integer,
|
||
zero, negative, and beyond-last page numbers; and maps page 1 back to the
|
||
unnumbered locale root. An empty root is a valid archive state, while no empty
|
||
numbered page is generated. Tests show that adding, removing, drafting, or
|
||
republishing catalog records changes the generated page inventory without a
|
||
manual route list.
|
||
|
||
The content publication manifest remains independent of the Library catalog.
|
||
`getLibraryPaginationManifest()` first receives the completed content manifest,
|
||
then derives the catalog and generated page descriptors from it.
|
||
`getRoutePublicationManifest()` composes and sorts those two inventories for
|
||
static route generation and sitemap output. This ordering avoids a recursive
|
||
manifest/catalog dependency. Generated pages reuse their locale's Library root
|
||
entry for presentation, while their publication descriptor supplies the
|
||
numbered route, self-canonical URL, eligibility, sitemap status, and page
|
||
metadata. The reserved `/{locale?}/library/page` families are checked against
|
||
content routes before generation, so content cannot silently shadow an archive
|
||
or alias.
|
||
|
||
The generated current-corpus inventory is:
|
||
|
||
| Language | Eligible articles | Routes and card counts |
|
||
| --- | ---: | --- |
|
||
| English | 46 | `/library` (10), `/library/page/2` (10), `/library/page/3` (10), `/library/page/4` (10), `/library/page/5` (6) |
|
||
| Spanish | 12 | `/es/library` (10), `/es/library/page/2` (2) |
|
||
| Arabic | 7 | `/ar/library` (7); no numbered page |
|
||
|
||
The implementation intentionally generates no `/page/1` HTML, English page 6,
|
||
Spanish page 3, Arabic page 2, page 0, leading-zero alias, decimal page, or
|
||
beyond-last page. Those absent paths fall through to the static host's 404
|
||
behavior.
|
||
|
||
### Rendering, Navigation, and Search
|
||
|
||
The three locale components now render the page slice returned by the shared
|
||
helper. Existing heroes, introductory content, cards, article URLs, featured
|
||
images, popular-post lists, and search controls remain in place. Page-specific
|
||
document titles append `Page N` or the existing locale's equivalent; the
|
||
visible root H1 is unchanged and remains unique. `BlogIndexLayout.astro` accepts
|
||
the heading separately from the document title so a numbered title does not
|
||
alter the source heading.
|
||
|
||
`LibraryPagination.astro` renders server-side anchors for previous, next, and
|
||
each valid page. Page 1 always links to the unnumbered root. The current link
|
||
uses `aria-current="page"`; the navigation has a locale-specific accessible
|
||
label, visible focus styles, 44-pixel minimum targets, wrapping layout, and no
|
||
disabled or nonexistent links. Arabic retains document RTL direction and
|
||
logical DOM focus order. The newly introduced Spanish and Arabic pagination
|
||
labels are functional but remain ready for human language review rather than
|
||
being represented as professionally reviewed translations.
|
||
|
||
The ordinary cards and pager share one archive wrapper. Phase 6B.1 search still
|
||
loads the full locale JSON index, including when initiated on a numbered page.
|
||
While search is active it hides both that page's cards and pager. Reset restores
|
||
the same numbered page without navigating to page 1. Direct fragments and
|
||
browser Back/Forward preserve the expected state. If index loading fails, the
|
||
page slice and pager remain usable. With JavaScript disabled, cards and real
|
||
pagination links remain fully navigable and the search enhancement stays
|
||
honestly unavailable. Legacy `/search` query and offset behavior is unchanged.
|
||
|
||
The historical Markdown listing snapshots remain bypassed and were not edited;
|
||
the catalog remains the only rendered listing source.
|
||
|
||
### First-Page Alias Redirect Definitions
|
||
|
||
The existing generator and redirect registry retain the three service aliases
|
||
and add exactly these definitions:
|
||
|
||
| Source | Destination | Status |
|
||
| --- | --- | ---: |
|
||
| `/library/page/1` | `/library` | 301 |
|
||
| `/es/library/page/1` | `/es/library` | 301 |
|
||
| `/ar/library/page/1` | `/ar/library` | 301 |
|
||
|
||
`src/data/redirects.json`, `reports/redirect-map.csv`, and
|
||
`reports/nginx-rewrites.conf` are generated from the same source definitions.
|
||
Tests reject duplicate sources, redirect loops, altered service aliases,
|
||
generated alias HTML, or alias sitemap entries.
|
||
|
||
An isolated `nginx:latest` container served the generated static output with
|
||
the generated snippet mounted read-only. Each alias returned HTTP 301 with its
|
||
exact path-only `Location`, following each redirect ended at HTTP 200 without a
|
||
loop, `/library/page/2` returned 200, and `/library/page/6` returned 404. The
|
||
container was stopped after the check. These results validate the repository
|
||
definitions and compatible nginx behavior only. Neither the NixOS reverse
|
||
proxy nor the deployed staging/production configuration was changed; activation
|
||
and host-level verification remain explicitly gated.
|
||
|
||
### Publication and SEO Results
|
||
|
||
The three Library roots preserve their existing self-canonicals and reciprocal
|
||
root hreflang relationships. Each generated numbered page is self-canonical,
|
||
`index,follow` in the local indexing-enabled build, present in that sitemap,
|
||
and deliberately has no hreflang. The five routes increase the generated HTML
|
||
count from 97 to 102 and the production-policy sitemap count from 92 to 97.
|
||
Hreflang remains 174 links across the same 53 routes.
|
||
|
||
The existing article routes, article canonicals, syndicated exceptions,
|
||
BlogPosting and FAQPage output, `/search` noindex behavior, LanguageSwitcher,
|
||
Header, Footer, forms, and integrations are unchanged. The final normal build
|
||
restored all 102 pages to global `noindex,nofollow`, an empty sitemap, and no
|
||
hreflang.
|
||
|
||
The saved-production offline reconciliation is
|
||
`reports/route-reconciliation-2026-10-10-offline-02-51-44-711Z.json`. It records
|
||
102 locally generated routes and reuses the existing 70 production requests
|
||
without making network requests or changing the historical observations. Its
|
||
production sitemap figures describe the preserved discovery baseline, not the
|
||
local indexing-enabled sitemap assertion above.
|
||
|
||
### Browser and Redirect Validation
|
||
|
||
A local Astro preview of the generated static artifact was exercised through
|
||
headless Chromium at desktop and 390-by-844 mobile viewports. Thirty-six focused
|
||
checks covered all three Library roots, English pages 2, 3, and 5, Spanish page
|
||
2, visible-link navigation, boundary controls, exact card counts, unique H1s,
|
||
mobile wrapping and overflow, Arabic RTL, and direct numbered URLs.
|
||
|
||
On `/library/page/3`, search found an article outside that ten-card slice,
|
||
hid cards and pagination, and restored the original page-3 archive on reset.
|
||
Direct search fragments and browser Back/Forward worked. Representative Spanish
|
||
search also used its full locale catalog. A blocked index request retained the
|
||
archive and pager. With JavaScript disabled, page-3 cards, article links, and
|
||
pagination remained available while search stayed unavailable. No claim is
|
||
made for a particular screen reader. The deployed `aia.web3app.dev` host was not
|
||
changed or used as evidence that the new redirect definitions are active.
|
||
|
||
### Automated Validation
|
||
|
||
| Check | Result |
|
||
| --- | --- |
|
||
| `npm run test:library` | Passed: 25 tests, including pagination boundaries, real corpus slices, route growth/removal, collisions, rendering, navigation, search, redirects, and SEO |
|
||
| `npm run test:seo` | Passed: 34 tests |
|
||
| `npm run test:publication` | Passed: 33 tests |
|
||
| `npm run test:markdown` | Passed: 20 tests |
|
||
| Normal `npm run build` | Passed: Astro check reported 0 errors, warnings, or hints; 102 HTML routes |
|
||
| `PUBLIC_ALLOW_INDEXING=true npm run build` | Passed: 102 HTML routes, 97 sitemap URLs, 174 hreflang links across 53 routes |
|
||
| `npm run audit:routes -- --check` | Passed after the established offline reconciliation procedure; no production requests |
|
||
| `npm run audit:links` | Passed: 0 broken internal links |
|
||
| `npm run audit:images` | Passed: 0 missing mapped page images |
|
||
| `npm run audit:blog` | Passed: 0 blog content audit failures |
|
||
| Final normal `npm run build` | Passed: 102 pages, all `noindex,nofollow`, empty sitemap, no hreflang |
|
||
| `git diff --check` | Passed |
|
||
|
||
### Cutover Blockers and Deferred Work
|
||
|
||
1. Production exposes `/library/page/6`, but the repository still lacks the
|
||
nine source-supported English articles assigned to Phase 6C. No empty page,
|
||
placeholder record, or misleading redirect was created. Phase 6C remains a
|
||
production-cutover prerequisite for accepting that URL.
|
||
2. Production's English author page 6 depends on the same missing corpus and on
|
||
Phase 6B.3 author archive implementation. No author route or author redirect
|
||
was added here.
|
||
3. Activation and HTTP verification of the three first-page redirects on the
|
||
intended hosting stack require a separately approved hosting change.
|
||
4. The Spanish and Arabic pagination navigation strings require human language
|
||
review. No article translation or translation relationship changed.
|
||
|
||
### Changed-File Inventory
|
||
|
||
Modified files:
|
||
|
||
- `reports/migration-summary.md` — this implementation, evidence, validation,
|
||
and cutover record.
|
||
- `reports/nginx-rewrites.conf`, `reports/redirect-map.csv`, and
|
||
`src/data/redirects.json` — generated first-page alias definitions while
|
||
preserving the three service aliases.
|
||
- `src/components/pages/LibraryEnglish.astro`,
|
||
`src/components/pages/LibrarySpanish.astro`, and
|
||
`src/components/pages/LibraryArabic.astro` — deterministic locale page slices,
|
||
pager integration, and separate numbered document titles.
|
||
- `src/layouts/BlogIndexLayout.astro` — separates the H1 from numbered document
|
||
titles and makes cards plus pager one search visibility boundary.
|
||
- `src/pages/[...slug].astro` — generates and renders composed numbered routes.
|
||
- `src/pages/sitemap.xml.ts` — uses the composed eligible route manifest.
|
||
- `src/utils/publication.ts` — composes content and generated Library page
|
||
descriptors through the existing publication API.
|
||
- `tools/generate-redirects.mjs` — adds the three approved Library aliases.
|
||
- `tools/library.test.mjs`, `tools/publication.test.mjs`, and
|
||
`tools/seo.test.mjs` — focused pagination, routing, search, redirect,
|
||
publication, sitemap, and metadata regression coverage.
|
||
|
||
New files:
|
||
|
||
- `src/utils/library-pagination.ts` — pure pagination and generated publication
|
||
descriptors.
|
||
- `src/components/LibraryPagination.astro` — accessible locale-aware pager.
|
||
- `reports/route-reconciliation-2026-10-10-offline-02-51-44-711Z.json` —
|
||
reproducible offline route evidence using the preserved production baseline.
|
||
|
||
No package dependency, article body, author record, content date, form,
|
||
analytics, advertising, production hosting, employee-portal, or unrelated page
|
||
was changed. Author archives, author biographies, Phase 6C content, page-1
|
||
author aliases, and production deployment remain outside this checkpoint.
|