Verify the source packet before designing the page

A source-linked report gives you a map back to evidence, but its locators can still go stale. Before writing HTML, freeze the report, the exact source files, and a hash list. Then reopen every citation attached to a number, limitation, issue status, recommendation, or approval state.

Our input was the four-page Harborlight Support Pilot Report created for the earlier PowerPoint-to-report workflow. Its central facts still matched the source packet: 72 cases were submitted, 54 completed, 46 formed the paired handling-time sample, the medians were 38 and 29 minutes, two P1 issues remained open, and wider rollout had not been approved.

The locators had drifted. The report pointed completed cases to M7 even though the frozen metrics extract defines that count at M3. The baseline and pilot medians pointed to M9 and M10, while the source records place them at M5 and M6. The feedback count pointed to M12 instead of M8. A closed issue appeared as ISS-083 instead of ISS-121, and the source register described M1-M12 even though the frozen extract ends at M8.

Six stale report references compared with corrected frozen source records for completed cases, handling-time medians, feedback, closed issue, and metrics range
A working link is insufficient when its locator no longer supports the adjacent claim. The preflight corrected six references before page construction. Credit: Grow AI Skills original editorial diagram. Open full-size image.

Each mismatch can attach the right claim to the wrong record. A link can open successfully and still fail to support the adjacent claim. We recorded all six corrections in the downloadable source-fidelity notes and treated the frozen source packet as authoritative. The conversion would have stopped if a value, status, recommendation, or approval state could not be reconciled.

Choose a reader task before choosing the interaction

The DOCX is organized as a report. The web page is organized around one pending decision: should the steering group end, extend, or expand the pilot on 25 September? That changes the reading order without changing the evidence hierarchy.

Report-to-page mapping

Report materialWeb treatmentReason
Executive summaryDecision status, scope, and evidence boundary at the topThe reader sees that wider rollout is unapproved before encountering promising results
Participation tableFour visible metrics, a simple bar view, and the complete data tableThe 46-case paired sample cannot be mistaken for all 72 submissions
Issue registerAll rows in HTML with optional All, Open, and Closed filtersThe steering group can isolate blockers without losing the frozen record
Appendix sourcesExact links beside material claims plus a source sectionThe reader can move from the decision page to the record that supports each claim

We added one custom interaction: an issue-status filter, because the two open P1 items control the rollout decision. We did not turn every section into tabs, carousels, tooltips, or animated cards. Extra controls would add focus behavior and hidden states without helping the reader judge the pilot.

Give the AI a conversion contract

The request should define source authority, protected claims, the reader's decision, allowed interaction, fallback behavior, and verification. Asking for a "modern interactive report" leaves all of those choices open.

Bounded report-to-web request
Convert the reviewed report and frozen S1-S4 source packet into a static
decision page for the Harborlight steering group.

Preserve every number, denominator, date, issue status, owner, limitation,
recommendation, and approval state. Treat the source packet as authoritative
when a report locator disagrees with it. Link material claims to an exact row
or statement. Do not add a forecast, benefit, quote, reaction, or new metric.

Use semantic HTML with one H1, logical headings, landmarks, a skip link,
descriptive links, table captions, and scoped headers. Keep the complete report
useful without JavaScript. Add only one interaction: native buttons may filter
issue rows by status. All rows must remain in the HTML and print in full.

Return files and test results. Do not claim WCAG conformance.

The downloadable full conversion prompt also locks the handling-time limitation, missing satisfaction score, missing annual-savings measure, source targets, reduced-motion treatment, and publication boundary. The AI can propose structure and write code inside that contract. Source authority and publication approval stay with the human release owner.

Build the complete reading path before adding JavaScript

The page starts with ordinary HTML: a skip link, header, labeled navigation, main content, logical headings, tables, links, disclosure elements, and footer. W3C's page-structure guidance explains how regions and headings help readers navigate and understand a page. We used those elements directly instead of recreating them with generic containers and ARIA.

Every issue row is present and visible in the initial document. JavaScript adds the filter controls by placing an enhanced class on the page. If the script does not run, the controls stay hidden and all three rows remain readable. Printing also restores every row, even if a reader had selected Open only on screen.

The evidence summaries use native <details> and <summary>. The HTML standard defines details as a disclosure widget for additional information or controls. It also warns against using it as a substitute for unrelated patterns such as tabs or menus. (HTML Living Standard)

Keep visual data available as structured data

The participation section includes four horizontal bars for submitted, eligible, completed, and paired cases. The bars are marked aria-hidden="true" because the same values, labels, definitions, shares, and source links appear immediately below in a visible table. No decision depends on color or bar length alone.

W3C's tables tutorial calls for structural relationships between header and data cells. The page therefore uses a caption, column headers with scope="col", and row headers with scope="row". W3C's guidance for complex images also recommends a short identification plus a complete text representation of essential chart information. A visible table is more useful here than trying to compress four stages and their denominators into alt text.

Add one progressive issue filter

The issue filter uses three ordinary buttons. Each button exposes its selected state with aria-pressed. Activating Open only hides the closed row and updates a polite live region to "Showing 2 open issues." Keyboard and pointer input reach the same code path.

Keyboard-focused Open only button and issue table showing the two open P1 records ISS-104 and ISS-117
The filter changes the visible rows and live count. All three rows remain in the HTML and return when scripts are disabled or the page is printed. Credit: Grow AI Skills retained local browser screenshot. Open full-size image.

The filtering code changes presentation only. It fetches no data, rewrites no issue status, and saves no preference. The frozen table remains the source of truth. This keeps the test surface small: initial rows, pressed state, visible count, live message, no-script behavior, and print restoration.

Test evidence and accessibility as separate systems

The Python evidence gate checks selected facts and relationships that a generic accessibility scanner cannot know. It verifies the required numbers, corrected locators, issue IDs, approval language, source targets, table captions, scoped headers, native buttons, progressive enhancement, print restoration, source hashes, and absence of prohibited positive claims.

The intact page passed 39 of 39 checks. We then made eight controlled mutations: restored the wrong completed-case locator, restored ISS-083, inverted the approval state, removed a caption, changed a filter into a submit button, broke a source target, hid an issue row before JavaScript, and removed the causal limitation. The gate rejected all eight. Download the gate and retained results.

The browser run covered a 1440 by 900 desktop viewport, 390 by 844 mobile viewport, 320 CSS-pixel reflow check, JavaScript-disabled context, print emulation, keyboard focus, filter state, native disclosure behavior, source targets, console health, and page errors. The retained Google Chrome 153.0.8010.50 run passed 25 of 25 checks. axe-core 4.12.1 returned zero violations and zero incomplete checks on both the report page and source book.

Retained results and evidence limits

Test layerRetained resultWhat it establishes
Source and structure gate39/39 checks passedThe selected fixture invariants are present
Mutation test8/8 damaging changes rejectedThe encoded checks fail on the tested regressions
Browser behavior25/25 checks passedThe tested interactions and layouts behaved as specified in one local Chrome run
axe-core 4.12.10 violations and 0 incomplete checks on both pagesThe executed axe rules did not report a finding in that environment

Keep the failed runs

The first browser run failed at 24 of 25 checks because the browser requested /favicon.ico and received a 404. The report content was unaffected, but a clean console was part of the contract. We added a data-URL favicon instead of teaching the test to ignore the error.

The next run passed the functional checks and produced no axe violations, but two automated checks remained incomplete. A generic status-row div carried an aria-label that was not well supported in that context. Six hero elements also needed manual contrast review because axe could not resolve text contrast over a CSS gradient. We replaced the generic status container with a semantic list and changed the gradient and translucent chips to solid colors. The following run returned no incomplete axe checks.

Retaining these failed runs shows which repairs were required before release. We repaired the page and reran the tests instead of approving it from appearance.

Read the accessibility result narrowly

W3C states that no evaluation tool alone can determine whether a site meets accessibility standards. Its Easy Checks resource is also explicit that a page can pass a preliminary review and still contain significant barriers. axe-core is useful for automated testing, and its own documentation says that manual review remains necessary for issues automation cannot determine. (axe-core documentation)

The retained evidence covers one synthetic decision page. It kept its selected facts and source links, worked with keyboard and pointer input in the tested browser, retained its content without JavaScript, reflowed at the tested widths, printed all issue rows, and produced no axe finding in the final run. We did not test a screen-reader and browser matrix, speech input, high-contrast modes, browser zoom on physical devices, disabled-user comprehension, other report structures, production headers, or a public deployment. Its release state is ready for owner and accessibility review; WCAG conformance remains unverified.

Release checklist

  • Freeze the report, source files, review date, and hashes.
  • Open every material locator and repair mismatches before changing the format.
  • Write the reader's decision and permitted interaction into the conversion contract.
  • Keep headings, tables, links, and core content complete before JavaScript runs.
  • Give every visual claim a visible text or table equivalent.
  • Test source fidelity, keyboard behavior, no-script behavior, reflow, print, console health, and automated accessibility checks separately.
  • Retain the failed runs and the exact corrections.
  • Stop publication when a material source does not resolve, essential content depends on script or color, keyboard focus disappears, or human accessibility review is still required for the promised release.