Turn the reference
into working code.
A complete, copyable local implementation boundary: source files, data schemas, state rules, verification, and change ownership.
Start in three steps
- 1
Choose a surface
Start with a route recipe and the object it presents. Use the independent family map to discover shared patterns.
- 2
Reuse the contract
Copy local tokens and component classes. Read states, keyboard behavior, constraints and source provenance.
- 3
Verify the result
Run the data and browser checks; compare the same viewport and content against frozen evidence.
node designs/raycast/reference-data/build-site.mjs
python3 -m http.server 4178 --directory designs/raycast/site
# In another terminal, from the repository root:
node designs/raycast/evidence/verification/data-contract-tests.mjs
.agents/skills/design-research/scripts/run-playwright.sh \
designs/raycast/evidence/verification/verify-site.cjs http://127.0.0.1:4178/Files you can use
| File | Responsibility | Change rule |
|---|---|---|
| assets/reference.css | Tokens, foundations, components, layouts and responsive / preference modes. | Shared visual change belongs here; avoid per-page token forks. |
| assets/reference.js | Local search, dialogs, forms, copy, tabs, filters and state demonstrations. | Use safe text insertion, explicit focus and no remote submissions. |
| data/fixtures.json | Synthetic valid, malformed, long and missing records. | Stable IDs; fixtures are not production facts. |
| data/implementation-contract.json | Strict schemas, state reducer, capabilities and acceptance budgets. | Breaking schema changes increment the contract version. |
| data/search-index.json.gz | Stable page/component/icon/source destinations. | Every href must resolve below the static base path. |
| data/component-geometry.json.gz | Original floats, source selectors, conditions and measured relationships. | Never rewrite measurements to match a preferred spacing scale. |
| data/css-component-coverage-ledger.json.gz | Independent denominator and source-backed weighted coverage. | New families/parts/states must appear before re-scoring. |
Data contracts
The local record schemas are strict authoring contracts. Unknown properties fail validation. Stable identity, bounded strings, safe local/official URLs, explicit nulls and cross-record plan/collection rules prevent common implementation ambiguity. PublicFeedback is a draft shape only; it does not describe a remote Raycast API.
Browse all fields and relationships{
"type": "object",
"additionalProperties": false,
"properties": {
"schemaVersion": {
"const": 1
},
"requestId": {
"type": "integer",
"minimum": 1
},
"state": {
"type": "string",
"enum": [
"loading",
"ready",
"empty",
"partial",
"stale",
"error",
"offline",
"permission"
]
},
"items": {
"type": "array",
"items": {
"$ref": "#/$defs/Extension"
},
"minItems": 0,
"maxItems": 500
},
"receivedAt": {
"anyOf": [
{
"type": "string",
"minLength": 20,
"maxLength": 30,
"format": "date-time",
"pattern": "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(?:\\.\\d{1,3})?Z$"
},
{
"type": "null"
}
]
},
"expiresAt": {
"anyOf": [
{
"type": "string",
"minLength": 20,
"maxLength": 30,
"format": "date-time",
"pattern": "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(?:\\.\\d{1,3})?Z$"
},
{
"type": "null"
}
]
},
"hasMore": {
"const": false
},
"message": {
"anyOf": [
{
"type": "string",
"minLength": 1,
"maxLength": 400
},
{
"type": "null"
}
]
}
},
"required": [
"schemaVersion",
"requestId",
"state",
"items",
"receivedAt",
"expiresAt",
"hasMore",
"message"
]
}State, routing, and events
| Event | Transition | Invariant |
|---|---|---|
| Query/category change | Synchronous filter, count and empty-state update; replace URL query. | No query leaves the browser. Explicit hash destination remains reachable under active filters. |
| Open overlay | Record opener→showModal→focus named input. | Only native modal owns trapped focus; close returns to a connected enabled opener. |
| Submit local form | Validate→pending 450ms→selected local outcome. | Invalid fields retain values; first invalid focuses; pending ignores duplicate submit. |
| Conditional feedback | Bug report shows subtype+feature; feature request shows feature; other categories hide/disable both. | Draft values are preserved when switching back. Hidden fields are excluded from the active shape. |
| Plan choice | Cadence and tier form one state; derive amount+unit+entitlements together. | No mixed annual/monthly label; no real checkout. |
| Clipboard | Await writeText→announce success; rejection→manual-copy message. | Do not claim copy succeeded before the promise resolves. |
| Media play | Explicit user activation→native controls. | No autoplay audio; no hidden loops; source fallback always available. |
Operational contract and risk boundary
| Area | Local contract | Private fact not claimed |
|---|---|---|
| Security | No eval, unsafe HTML insertion, tracking, external fonts or remote form submission. Safe URL whitelist for dynamic links. | Production headers, backend validation or account authorization. |
| Privacy | Synthetic fixtures; no cookies, localStorage or persistent draft. Filenames rendered as text. | Raycast’s internal collection, retention or telemetry behavior. |
| Failure | Preserve query/draft; distinguish missing data, no matches, offline and permission. | Private outage or retry policy. |
| Performance | Static resources, lazy images, shared local modules, self-hosted fonts; catalogs tested under large inventory. | Native app launch time or backend SLOs. |
| Compatibility | Current Chromium evidence; semantic HTML and native controls; narrow/zoom/preferences tested. | Untested browser engine parity or assistive technology certification. |
| Maintenance | Versioned local contract, dated source records, explicit change review and repeatable build. | Official ownership, roadmap or support commitment. |
Complete implementation handbook
Raycast public reference: implementation contract
This package supports extensions to a static, reconstructed reference of Raycast’s public website. Its CSS classes, DOM bindings and data schemas are local contracts. They do not describe Raycast’s private website APIs, account database, native application internals or production telemetry. Initial public evidence was captured on 18 September 2026, with separately dated public-source recovery on 19 September; a new public release does not silently update this snapshot.
Start with the machine-readable contract, synthetic fixtures and the four handoff briefs. The original fixture bundle retains six object types, 26 valid records, 26 deliberately malformed records and nine collection snapshots. Additive strict schemas and fixtures in site/data/family-fixtures.json cover the fourteen independently inventoried public object kinds; family-objects.html shows their relationships and local representations. People in the fixtures are fictional; email addresses use example.com. Unsafe strings occur only as inert test input.
The package distinguishes three executable boundaries. reference.js drives the shared guide controls; family-reference.mjs drives the route compositions, and family-ui-model.mjs supplies browser validation and state contracts. The full pure source, family-model.mjs, also provides the Node data and relationship checks. data-contract-tests.mjs validates authoring data and a deterministic collection model. The four junior tasks require a separate implementer to build and verify extensions to a frozen copy. Passing the data tests does not pass the browser checks or the junior challenge.
Sources and ownership
All paths below are relative to designs/raycast/. The published site must expose copies or readable views of the referenced contracts; a link outside site/ is not a deployable website link.
| Concern | Source of truth | Owner and change rule |
|---|---|---|
| Public denominator | reference-data/independent-component-inventory.json and public route captures | Independent inventory researcher; expected families come from public discovery, not the finished specimens. |
| Component anatomy, variants and recipes | reference-data/catalog.mjs | Reference maintainer; keep stable component IDs, then regenerate pages and ledgers. |
| Local token values, layout and modes | site/assets/reference.css | Reference maintainer; computed local output resolves a disagreement with prose. Record and repair the discrepancy. |
| Current interaction | site/assets/reference.js | Reference maintainer; its native elements, selectors and exported helpers are the runtime API. |
| Data shapes and ingestion | reference-data/implementation-contract.json | Reference maintainer; $defs and crossRecordRules apply together. |
| Example data | site/data/fixtures.json | Reference maintainer; valid records and deliberate rejections stay separate. |
| Public appearance | evidence/capture/, evidence/capture-final/, evidence/capture-more/, evidence/inventory/ | Evidence researcher; preserve route, time, role, viewport, state and source script. |
| Source CSS and geometry | reference-data/css-source-ledger.json, component-geometry.json, css-component-coverage-ledger.json | Evidence researcher; preserve hashes, selector ownership, cascade conditions and unmatched rows. |
| Icons, fonts and images | reference-data/icon-asset-ledger.json, asset-source-inventory.json, site/assets/ | Asset maintainer; keep rights, source and replacement restrictions with the asset. |
| Private boundaries | reference-data/contract-recovery-ledger.json | Evidence researcher; retain recovery attempts and the exact condition for later verification. |
| Data checks | evidence/verification/data-contract-tests.mjs and data-contract-results.json | Verifier; rerun after any input changes and retain the reported hashes. |
| Browser checks | evidence/verification/verify-site.cjs and its results | Verifier; record actual browsers and states tested. |
| Junior execution | reference-data/extension-briefs.json, evidence/junior/ | Independent junior evaluator; a written brief earns no implementation or verification pass. |
| Release and assessment | ITERATION-LOG.md, BENCHMARK-REVIEW.md, .benchmark-score.json | Release operator and independent judges; assess the exact frozen version. |
The visual reference comes from the public Store, pricing page, Notes page, blog and feedback page. Their retained evidence paths appear in implementation-contract.json.sources. The public extension repository and the retained @raycast/api package establish a native extension ecosystem; they do not establish website service schemas. Importing the native SDK is unnecessary for this static reference.
Build, run and check
Run these commands from the repository root. Site generation and data checks need Node 22 or later. The static build also uses pinned, locally vendored PostCSS and CSS-tree parsers in reference-data/vendor/; their source and licenses are included. Serving the site needs Python 3.10 or later. There is no dependency download, account setup, API key or bundler step.
Browser checks use the repository’s globally resolved Playwright package and installed Chromium. The captured environment used Node 24.13.1, Playwright 1.62.1 and Chromium 152.0.7977.42. The wrapper sets NODE_PATH from npm root --global; set DESIGN_RESEARCH_CHROMIUM to an executable Chromium path only when using another host. A version string alone is not a launch check.
node --version
python3 --version
.agents/skills/design-research/scripts/verify-browser-stack.sh
node designs/raycast/reference-data/build-site.mjs --standalone-report evidence/verification/remediation-round5/standalone-icons/results.json
node designs/raycast/evidence/verification/data-contract-tests.mjs
python3 -m http.server 4178 --bind 127.0.0.1 --directory designs/raycast/siteKeep the server running. In a second terminal, run:
.agents/skills/design-research/scripts/run-playwright.sh designs/raycast/evidence/verification/verify-site.cjs http://127.0.0.1:4178/
.agents/skills/design-research/scripts/run-playwright.sh designs/raycast/evidence/verification/check-system.cjs http://127.0.0.1:4178/Open http://127.0.0.1:4178/implementation.html for the guide and handoff.html for the tasks. Stop the server with Ctrl+C. If port 4178 is in use, choose another unprivileged port and pass the same URL to the verifier. Do not terminate another process to free the port.
The recorded build selects the actual standalone SVG verification report explicitly. If that report is absent or its pinned inputs changed, reconciliation leaves the affected claims unverified; a build cannot substitute for execution. Historical default selection remains available for reproducing prior tooling.
build-site.mjs generates the static HTML, catalogs and search index. Change authored inputs, then rebuild; editing generated HTML alone will be lost. The build regenerates the 47 route-family compositions and the asset-quality page as well as the base guide. The build is not a test. The data checker returns a failure for a rejected invariant and records not-run when the generated search index is absent. The browser checker covers the built pages. Read the result files rather than assuming that the presence of a script proves execution.
Source recovery scripts serve archived public documents and assets to isolated Chromium contexts, block unarchived requests and produce evidence under evidence/verification/. They do not submit forms or authenticate. Run recover-css-matches.cjs through the same Playwright wrapper to recover native selector specificity and source declarations. compare-source-replay.cjs renders the archived documents against the original public measurements; node designs/raycast/evidence/verification/evaluate-source-comparisons.mjs checks component geometry and retains absolute page-placement drift separately.
verify-derived-replay.cjs independently rerenders the exact local part contracts named by derived-replay-input.json. Its frozen expected files are under source-replay/; each comparison retains their hashes. The initial full run and the later keyboard font-dependency closure remain separate reports. verify-source-derived-variants.cjs compares two public CSS modifiers with independently written local CSS at 390 and 1,440 px. Those modifiers preserve the 880 px navbar condition and the testimonial animation-end state. These local contracts do not establish production triggers, private account states or the animation frame of an uncaptured live element.
After those checks, run node --max-old-space-size=8192 designs/raycast/evidence/verification/normalize-geometry.mjs. The full evidence normalization can use several GB of memory; normal site development does not load it. A changed expected capture invalidates its old comparisons. Normalize the new measurements, run node designs/raycast/evidence/verification/freeze-derived-input.mjs, execute verify-derived-replay.cjs, then normalize again. Run reference-data/remediation/collect-coverage-proofs.mjs with the actual current execution reports, then reference-data/remediation/reconcile-coverage.mjs and build-site.mjs. Do not run the legacy normalization after the reconciler; that would replace the reconciled status projection. Source replay and authored-composition evidence remain separate before any coverage claim. Unresolved selectors, animation-frame differences and resource failures remain explicit Partial records. The generated component-geometry-summary.json and css-component-coverage-summary.json omit declaration/style pools and are download-only publication data. Guide runtime checks remain a separate verification boundary.
The guide uses a derived Geist Mono Latin/technical subset at site/assets/geist-mono-latin-reference.woff2 to meet its font-transfer budget. reference-data/font-subset.json records the original and derived hashes, retained glyphs, variable weight axis and encoded advance-width checks. The original source font stays in evidence; synthetic asset fixtures that name original files retain their original hashes. This subset is a local packaging choice, not a claim that Raycast delivers that binary.
Observed SVG exports in assets/observed-icons/ are standalone image documents. evidence/source-assets/observed_svg_exports.py adds a missing SVG root namespace to a derived export while preserving geometry and the original retained source bytes. publication-assets.json records each source hash, output hash and transform separately; the source-derived filename is not a claim that transformed bytes retain the original hash. Run python3 designs/raycast/evidence/source-assets/observed_svg_exports.py to regenerate these exports. verify-standalone-icons.cjs checks each real external image decode, XML geometry and the generated atlas consumers.
assets/fallback-fonts.css supplies licensed Japanese and Devanagari fallback faces after the captured brand fonts. Their Unicode ranges load only for missing script glyphs. They are original guide additions; reference-data/remediation/local-fallback-fonts.json retains the source, rights and codepoint evidence. The type-role matrix verifies the font actually used to render Japanese text through Chromium’s platform-font records. A family name in computed CSS alone does not prove that readable glyphs rendered.
Run node --max-old-space-size=8192 designs/raycast/evidence/verification/verify-geometry-contracts.mjs to audit part ownership, source pointers, preserved subpixels, current hashes and coverage arithmetic. The original pointer denominator is 42,629 geometryEvidence entries plus one additionalInlineSourceOccurrences child: the public account-confirmation error at evidence/inventory/closure/confirmation-entry-1440.json, geometry[16].children[0], for a historical total of 42,630. The separately recorded lightbox addition contributes 98 exact pointers, giving 42,727 top-level pointers and 42,728 including that child. Its additive audit preserves the original normalization and separately checks the new bindings; rerunning the legacy normalizer would overwrite reconciled evidence. That child retains its measured box and an explicit Partial styling contract; its uncaptured computed styles are not invented.
The publication root is only site/. Raw production CSS, response bodies, private evidence paths and original capture HTML remain outside it. Internal links use sibling filenames and relative asset paths; test a deployment beneath a path prefix as well as /. Opening HTML with file:// does not exercise the fetch-based search index and is not a supported test mode.
Page and component API
The landing and guide pages are index.html, scope.html, product-map.html, diagrams.html, surfaces.html, foundations.html, typography.html, assets.html, icons.html, components.html, families.html, family-probes.html, patterns.html, objects.html, content.html, implementation.html, evidence.html and handoff.html. Nine surface-*.html pages render base public compositions: home, Pro, pricing, Store, extension, feature, feedback, article and keyboard. family-reference.html links all 47 family-specific pages, family-objects.html covers the fourteen object kinds, and asset-quality.html exercises fonts, semantic icons and media alternatives. reference-data/site-build.json is the generated page inventory. Public source routes such as /store are evidence labels, not routes served by this package. A new local page is another sibling HTML file; it needs no server rewrite.
Each document owns its title, one h1, one main, skip target, active navigation link and section IDs. The fixed navbar owns site navigation. A page’s toolbar owns collection search and category. Native dialogs own modal focus. The document owns the polite #announcer and transient toast. Preserve source order when columns stack.
Load the shared stylesheet and ES module once:
<link rel="stylesheet" href="assets/fallback-fonts.css">
<link rel="stylesheet" href="assets/reference.css">
<script type="module" src="assets/reference.js"></script>The shared module imports read-json.js and media-lifecycle.mjs. It loads reference-forms.mjs, reference-collections.mjs and reference-catalogs.mjs only when their controls exist; the forms controller imports family-ui-model.mjs, the generated browser subset of family-model.mjs. Retain all sibling modules. data-reference-ready="true" on the document root means the selected controllers finished initialization; a module-load failure records failed and displays a retry message. The stylesheet also imports the fallback face definitions so an existing page that loads only reference.css still receives them. Budgets count the loaded dependency graph.
Modules created under site/assets/ can import these helpers:
import { copyText, openDialog, toast } from './reference.js';| Export | Inputs and result | Exact behavior |
|---|---|---|
copyText(text, trigger?) | String and optional element; Promise<boolean> | Writes only after an explicit user action. Success announces the copy and changes the trigger text for 1,800 ms. Failure returns false and leaves visible source text available for manual copy. |
openDialog(dialog, trigger?) | Native dialog and optional opener; no return value | Ignores an absent or already-open dialog, records the opener, calls showModal() and focuses the first input/autofocus/button/link in document order. Close returns focus to a connected, enabled opener. |
toast(message) | Plain string; no return value | Creates or reuses a role=status node. Last message replaces the earlier one and restarts its 4,000 ms timer. There is no queue or persisted history. |
safeLocalHref(value) | String; original string or null | Runtime guard for same-package page/resource links. It rejects controls, backslashes, encoded slash/backslash/NUL, schemes, leading slashes and parent paths, then checks origin and package prefix. Apply the stricter LocalHref schema to navigation data first; this helper also permits assets. |
The module binds existing elements when it runs. A dynamically inserted control must either use an explicitly attached handler or exist before this module initializes. Do not assume event delegation for every data-* attribute.
| Binding | Required relationship | State owner |
|---|---|---|
[data-filter="catalog-id"] | One input, a matching container of [data-search] items; optional [data-category-for], [data-count-for], [data-empty-for] | Page URL and current DOM. First toolbar owns q/category; later toolbars own q_<container-id>/category_<container-id>. |
[data-copy] or [data-copy-target] | Literal copy text or an existing visible text element ID | Clipboard helper; source text remains visible on rejection. |
[data-dialog="dialog-id"], [data-close-dialog] | Existing native dialog with labelled title and explicit close | Dialog and opener WeakMap. Native Escape closes. |
[data-popover-toggle] | aria-controls, aria-expanded, a panel inside .popover-anchor | Trigger and panel. Open focuses the first actionable child; Escape/outside press closes. |
[data-tabs] | role=tab controls with aria-controls; labelled panels | One aria-selected=true, roving tabindex, hidden inactive panels. |
[data-segmented] | Buttons with data-value, one aria-pressed=true | Group dispatches bubbling selectionchange with detail.value. |
[data-pricing] | Native radios with [data-billing], a unique name per pricing group, and data-price-annual/data-price-monthly values | Local amount/cadence preview; never a purchase or permission change. |
form[data-local-form] | Submit control, feedback region, labelled fields and optional mode select | Current document only; no request or persistent draft. |
[data-state-demo] | A select plus [data-state-output] | Message specimen only; it does not load or retain collection data. |
Use existing component classes before introducing another variant. .extension-card owns 24 px padding, 16 px internal gap, 12 px radius, a 1 px border and 16/24 px title text. .extension-grid owns its columns and 24 px inter-card gap. The grid uses three columns from 880 px, two at 720–879 px and one below 720 px. A card must not add an outer margin to reproduce the grid gap.
The main container is at most 1,204 px with 24 px page gutters; below 720 px, gutters are 16 px. Reading content is at most 746 px. Other shared thresholds are 480, 880 and 1,200 px. Exact exceptions belong in the component geometry ledger, not a rounded replacement spacing scale.
Data contract and examples
implementation-contract.json.dataSchema uses the JSON Schema 2020-12 shape with local definitions in $defs. The test runner evaluates the assertion keywords used in those definitions and rejects an unsupported keyword; it is not a general JSON Schema library. Every record has a strict field set. Nullable keys are present with null; an omitted required key, wrong type or invented field is malformed. IDs are stable lowercase slugs, not display text or array positions.
| Type | Fields a consumer uses | Missing and boundary behavior |
|---|---|---|
Extension | id, slug, name, summary, publisher, category, platforms, iconAssetId, publicUrl, commands, access, updatedAt, locale, tags, downloadCount, revision | Null summary/publisher/icon/count use named fallbacks. access is public, sign-in-required or unavailable in the fixture. It never proves a real account’s access. |
Plan | id, name, description, audience, pricingMode, currency, monthlyUsdCents, annualMonthlyUsdCents, featureIds, ctaLabel, ctaHref, updatedAt, revision | Free has two zero values; fixed has positive integer cents; contact has two null prices. Contact never displays $0. |
Article | id, slug, kind, title, summary, author, publishedAt, updatedAt, category, locale, coverAssetId, publicUrl, blocks, revision | Omit missing author/date; retain useful text if cover is absent. Body blocks contain plain text, never HTML. |
Feature | id, title, summary, platforms, entitlementLabel, availabilityLabel, mediaAssetId, publicUrl, relatedFeatureIds, updatedAt, revision | unverified is a visible evidence boundary. Do not infer entitlement from a selected plan. Related features are one-hop links, not recursively rendered content. |
PublicFeedback | id, category, senderEmail, appVersion, bugType, feature, message, attachments, submissionState, createdAt | Synthetic validated record; an unfinished DOM draft can be incomplete. Messages and selected files remain in memory. No record is sent. |
Asset | id, kind, mimeType, localPath, sourceUrl, dimensions, byte length, SHA-256, alt, decorative, theme, loading, rights | File must exist inside site/assets/ with matching bytes/hash. Decorative alt is empty; informative images have text. Font dimensions are null. |
For example, draft-notes is a fictional extension with platforms: ["macos", "windows"], category: "productivity", revision: 1 and an official Store source link. missing-metadata has null optional metadata; rtl-notes has Arabic text; literal-markup has an <img ...> string that must stay text. Do not replace these with real private account data.
Older conceptual labels map as follows: extension title → name, description → summary, author → publisher, canonicalUrl → publicUrl; article bodyBlocks → blocks; feedback email → senderEmail, version → appVersion, attachment size → byteLength, type → mediaType. These are reading aids, not alternate accepted input fields. The schema rejects old field names until a versioned migration converts them.
Keep money as integer cents. A local Pro example has monthlyUsdCents=1000 and annualMonthlyUsdCents=800. Divide by 100 only for display; use Intl.NumberFormat('en-US', { style: 'currency', currency: 'USD', maximumFractionDigits: 0 }) for these whole-dollar examples. Show “per person / month” and the selected billing cadence together. The annual figure is a monthly equivalent, not an amount to charge. Fixtures are synthetic reference values and are not a current commercial offer.
Store dates as valid UTC ISO strings. Display dates with Intl.DateTimeFormat('en-GB', { day: 'numeric', month: 'short', year: 'numeric', timeZone: 'UTC' }); add explicit UTC when displaying a time. Use the original timestamp in <time datetime>. A missing date is absent or “Date unavailable”, never today. Counts use integer grouping, singular at 1 and plural otherwise; null is “Count unavailable”, not zero.
The fixture states and their presentation are explicit:
| Fixture or condition | Representation and recovery |
|---|---|
initial-loading | No rows, “Loading extensions”, busy result region; placeholders are decorative. |
ready | Accepted rows. The stock message selector calls this success; the data envelope calls it ready. |
empty-source | No data exists in the fixture: “No extensions yet”; offer the public Store source. |
| Filter returns zero | Data exists but does not match: “No matching extensions”; clear query while preserving category. This is not an empty source. |
partial-source | Keep usable rows, explain that some are unavailable and expose one explicit retry. |
stale-source | Keep the dated snapshot and state that it is saved data. Stale begins at expiresAt <= now. |
offline-with-snapshot | Keep the last accepted rows and query; offer reconnect/retry. This does not promise offline first load. |
error-with-snapshot | Keep work, name the failed refresh and allow retry; no automatic loop. |
permission-boundary | Clear rows; explain the boundary and link to official sign-in. A hidden copy of private rows is not sufficient. |
rtl-narrow-offline | Arabic text, 390 px viewport, preserved rows and offline notice; URLs/IDs remain LTR inside bdi. |
The stock state selector demonstrates copy and announcements. It is not a remote Store client. The deterministic reference adapter in the data tests specifies how a junior extension should behave when it actually consumes the snapshots.
Collection ingestion, ordering and races
Validate each object before rendering. The adapter accepts at most 500 incoming extension records and never silently truncates a larger batch into a success. Drop malformed records and report a problem count without logging raw payload text. If valid siblings remain, state is partial; if every row is malformed, state is error. A valid empty response is empty.
Preserve the first accepted position of each ID. For repeated IDs, keep the highest revision. Ignore an older revision. Discard an identical repeat at the same revision. Contradictory records at the same highest revision quarantine that ID and mark the collection partial or error; a strictly newer valid revision resolves the conflict. Equality compares canonical object values, not property insertion order. Never merge fields from two contradictory records.
Inject the clock in tests: fixtureClock is 2026-09-18T23:00:00Z. A dated snapshot expires after its explicit expiresAt; do not age the published evidence by relabeling the capture date. All non-loading fixture envelopes have valid receivedAt and expiresAt with expiry at or after receipt. Loading has both null.
The latest issued request ID owns a commit. If request 3 finishes after request 4, response 3 cannot overwrite 4. An unissued response 5 also cannot commit while the issued ID is 4. Cancellation advances the issued ID. Access revocation is a separate guard and clears rows even when a stale response is arriving. Offline/error can retain the last in-memory public snapshot; a permission result cannot.
Future local data loaders use a 10-second timeout, an explicit retry and one pending attempt. These are reconstructed acceptance rules; the shipped form has a fixed 450 ms local demonstration and no network timeout. No optimistic account change, background retry, auto-sync, infinite loading or virtualized list is part of this reference. If a new page needs one, introduce a new versioned contract and tests first.
Routing, filters, selection and persistence
The first [data-filter] in document order reads q and category. Each later toolbar reads q_<container-id> and category_<container-id>, where <container-id> is its data-filter value. For example, data-filter="observed-icons" on the second toolbar owns q_observed-icons and category_observed-icons. URLSearchParams.get takes the first repeated value. Trim query edges. For matching, apply Unicode NFKD, remove combining marks U+0300–U+036F and lowercase with locale en. Search is a single substring over data-search; it is not fuzzy search, token AND or word reordering. Category matches the complete data-category string exactly. A label such as Account & feedback is one category; do not split it on spaces. Search and category combine with AND; results preserve authored DOM order.
On each input or category change, the runtime uses history.replaceState. It keeps other toolbars’ parameters, unrelated query parameters and the fragment, removes its own empty query and default category=all, and collapses repeated recognized parameters. Keep toolbar DOM order stable because the first toolbar owns the unprefixed keys. An unknown category becomes All and is removed during initial canonicalization. A Clear query button clears only q, keeps category and focuses the input. A Reset all action must set the category to All before dispatching input.
For example, components.html?q=%20Copy%20&category=unknown&origin=handoff#copy becomes components.html?q=Copy&origin=handoff#copy. Keystrokes do not create a browser history entry. Native page links do; Back returns to the prior page and normal browser scroll restoration. Reload restores catalog state from the URL.
A direct component/icon fragment must be reachable even under a filter. The runtime decodes its ID and reveals a hidden target without changing the query or category. The container count becomes “N visible items · includes linked item”, including that extra target, and its empty notice hides. The next filter edit applies the selected filters normally and may hide that extra target again. A malformed encoded fragment is ignored without throwing.
Global search is separate. It loads data/search-index.json.gz once through readJson and matches normalized title, category, keywords and control aliases. Exact titles rank first, then title or alias matches, then broader matches; the build keeps components and working examples ahead of coverage records within the same rank. reference-data/search-discovery.mjs owns stable control IDs and common terms such as button, input and dropdown. Results use 40-link pages, with a visible result range and Previous/Next controls, so every match remains reachable. A changed query returns to page one; changing the result page focuses its first link. It does not write q or category. Ctrl/Cmd+K and the visible button open the same native dialog. ArrowDown from the input enters results; Up/Down move without wrapping; Up on the first result returns to the field. Enter in the input follows only when there is exactly one result. Escape returns focus to the opener. Reopening in the same document keeps the query; reload resets it. If the index fails, navigation remains usable and the dialog explains the failure.
Tabs activate and focus on Left/Right/Home/End, wrapping at the ends, with one tab stop and one selected panel. Segmented buttons use the same directional keys and aria-pressed; only the selected button has tabindex=0, and inactive buttons have tabindex=-1. Neither control adds URL or durable state. Focus is not collection selection. Cards are ordinary links; the reference has no range, multi-select, select-all, bulk mutation or cross-page selection.
Persistence is limited to URL state and current-document memory. Menu/dialog state, form entries, selected file descriptors, billing preview, tabs and toast timers are transient. The reference writes no localStorage, sessionStorage, IndexedDB, service worker cache or application cookie. Browser form restoration or HTTP caching may occur independently; the package does not promise draft recovery after refresh or offline first load.
Feedback and conditional fields
The observed public feedback form provides category, email, version, description and attachments. Its Bug Report branch is retained in evidence/inventory/closure/feedback-select-bug-report-confirmed-1440.json and the adjacent HTML. No feedback was submitted during research.
Local category IDs map to Feature Request, Bug Report, Billing Issue, iOS and Other. Selecting bug-report reveals two controls after version and before description. Bug type defaults to not_working (“Not working as expected”), with crashing (“Raycast Crashing”) and freezing (“Raycast Freezing”). Feature starts at the “Select a feature” placeholder. Its 23 captured choices are AI, Applications, Auto Quit, Calculator, Calendar/My Schedule, Clipboard History, Cloud Sync, Custom Themes, Deeplinks, Dictation, Extensions, Flight Tracker, Focus, Hyper Key, Notes, Quicklinks, Script Commands, Search Files, Settings, Snippets, Store, Window Management and Other.
Feature Request reveals the Feature select without bug type; this branch is retained in evidence/inventory/route-tail/feedback-category-feature-request-1440.json. Bug Report reveals both. Billing Issue, iOS and Other use only the base fields. Feature selection is optional in this local contract; production requiredness is not inferred from a hidden native select. A non-bug canonical record has bugType=null; only Bug Report and Feature Request can retain a non-null feature. Hidden controls are disabled and leave the tab order. Keep their draft values in document memory so switching back does not erase a selection, and preserve email, version, message and attachments across every category change. Revealing fields does not move focus.
On local submit, prevent the default action and ignore duplicate attempts while pending. Validate the named form fields through feedbackDraftFromForm and validateFeedbackDraft in the browser module family-ui-model.mjs (generated from family-model.mjs): trimmed email, a required non-whitespace message of at most 4,000 Unicode code points, an optional version of at most 40 code points, category-dependent fields and the complete attachment selection. An astral character counts once; no UTF-16 maxlength silently truncates it. Focus the first invalid field, set aria-invalid, link visible help/error and preserve all values. Editing a field removes its invalid marker. Valid input disables the submit button, marks it busy and shows “Checking…” for 450 ms. Success says “Example validated. No data was sent or stored.” Simulated error and offline messages retain the draft and expose retry. The selected mode is a specimen control, not connectivity detection.
Attachment selection is at most five files, each at most 20 * 1024 * 1024 bytes. Store only descriptors (name, byteLength, mediaType) in fixture data. Do not read bytes, create data URLs, persist filenames or upload. File names are literal text and cannot contain a filesystem path in fixtures. The file control is inside the feedback form and participates in submission validation. A rejected selection preserves text and selected descriptors; correction clears the error. FeedbackDraft/DraftAttachment accept ordinary browser metadata separately from the intentionally narrower synthetic PublicFeedback/Attachment fixtures. The runtime checks count and size; the public accepted-type list is evidence, not a claim that the reference has a content scanner. When the lazy forms controller starts, it also validates the current native FileList, including any selection made before its change listener was installed. The displayed names, error state and Clear control therefore reflect early selections. Clearing files returns focus to the native input and preserves the message.
Author local forms with method="dialog" so a module-load failure does not fall back to a GET containing an entered email or message. The sign-in specimen includes an optional transient password field to demonstrate the observed entry mode. It never verifies, logs, persists or sends credentials. There is no POST endpoint, email delivery, queued submission, real feedback mutation or account recovery transaction.
Capabilities and private exclusions
Anonymous readers can inspect public references, filter, search, change local specimen state and explicitly copy visible text. Clipboard access still depends on browser permission. Readers may follow an explicit official source/sign-in link. Local forms only validate. Every local role is denied account editing, payment, invitations, real feedback submission, installation and private collection mutation.
Public plan names describe marketing evidence; they are not a local authorization system. A billing selector cannot grant access. An offline flag cannot expose a denied collection. The role in these captures is anonymous, not “administrator with unknown permissions”.
| Recovery ID | Retained public attempt | Practical exclusion and later verification condition |
|---|---|---|
PRIVATE-ACCOUNT | evidence/inventory/boundary/settings-boundary-1440.json; /settings/sessions reached official sign-in with a return path | Account settings, session invalidation and private errors are unobserved. Later verification needs authorized account access and a defined read-only inspection scope. |
PRIVATE-BILLING | evidence/inventory/boundary/upgrade-boundary-1440.json plus public pricing | No checkout, invoices, tax, proration, refunds or billing authorization claim. Later verification needs an authorized, approved non-charge test environment. |
PRIVATE-ORGANIZATION | Organization-creation route in evidence/inventory/state-routes.json and associated captures | No tenant role hierarchy, invite lifecycle, admin permission or audit-retention claim. Later verification needs an authorized test tenant and multiple roles. |
NATIVE-RUNTIME | Public SDK/docs/package evidence under evidence/source-assets/public-source/ | No installation, OS prompt, keychain, OAuth, native editing or sync claim. Later verification needs an approved native environment and test extension. |
PRIVATE-WEB-API | Public repository/package lookups in evidence/source-assets/public-source/fetches.json | No private server endpoint, experiment assignment, production schema or telemetry claim. Later verification needs versioned first-party documentation or authorized source access. |
Each row links to the matching entry in contract-recovery-ledger.json. That ledger must show the actual search, source recovery, reconstruction and comparison work before assigning private-verification-unavailable. This document names the boundary; it does not independently declare a public search exhausted. These exclusions limit product claims and leave local public-reference work testable.
Content and safe rendering
Use textContent for titles, messages, filenames, source labels and query feedback. Code belongs in literal <pre><code>. A fixture containing <script> or <img onerror> must render those characters; it must not create an element or event handler. Never use innerHTML, DOMParser, eval, a generated function, inline event attributes or CSS interpolation for supplied text.
Validate links before setting href, not only after a click. Local navigation permits a sibling lowercase .html filename with an optional query and safe fragment, or a safe fragment by itself. Reject absolute URLs in the search index, //, path traversal, backslashes, controls, javascript:, data: and custom app protocols. Official product links permit HTTPS on exactly raycast.com or www.raycast.com without credentials. Other recorded asset-provenance domains are evidence links with their own rights record; they are not automatically valid user destinations. Do not implement an arbitrary return_to, redirect or external URL parameter.
Keep essential labels, errors, pricing units, access explanations and attribution fully visible. Wrap titles and URLs; use .long-string for unbroken identifiers. Only extension preview summaries clamp to two lines, with full text available in the corresponding detail/disclosure. Do not show “null”, “undefined” or a fabricated value when metadata is missing.
Public captures are English. Local resilience fixtures include Arabic and mixed-script text; those tests do not prove Raycast localization. Set lang and dir=auto at the content boundary. Use logical spacing. Keep URLs, IDs and code inside bdi dir="ltr"; do not mirror logos, screenshots or ordinary nondirectional glyphs. A 30% expanded pseudolocale is a local layout test, not translated production copy.
Privacy, analytics and failure limits
The reference has no analytics SDK, telemetry endpoint, fingerprint or user identifier. The guide uses browser events and the local selectionchange custom event. Family pages additionally keep a bounded in-memory inspection log described below; it is never transmitted or persisted. Reserved names in the contract (catalog_filter_changed, reference_copy_result, local_form_result) are possible test-only events, not implemented tracking. If a later test uses them, include only category/count/result; exclude query text, email, message, copied text, filenames and IDs.
Automatic network activity is same-site static GETs only. Source links can leave the site after an explicit click. Do not forward a local query, draft or attachment name to those links. Browser request interception must assert zero non-GETs and zero automatic third-party requests across local flows. Source scanning alone cannot prove network behavior.
The site has no tenant database, destructive action, account token, moderation queue or regulated-data workflow. The optional account-entry password control is transient UI only and is never sent, validated against an account, or retained after its mode is left. Their fallback is a visible official-source boundary, not a fabricated backend. Do not add secrets, actual personal records, cookies or raw diagnostics to fixtures, published screenshots or console output. Asset rights and attribution still apply to a private reference; a public URL is not permission for unrestricted redistribution.
Offline loaded content can remain readable. An uncached first visit while offline can fail at the browser boundary because there is no service worker. Missing fonts use system sans/monospace fallbacks. Missing media retains its reserved area, caption and source link. Clipboard failure retains selectable text. Script failure leaves native navigation and disclosures usable and forms inert. Publish rollback restores the prior static artifact; it cannot repair or mutate a Raycast account.
Global search distinguishes loading, failed, no-match and ready states. It reads the byte-identical data/search-index.json.gz through readJson. A failed request exposes a named retry and retains the typed query. Navigation and an already loaded index continue to work offline. media-lifecycle.mjs pauses optional audio/video on document hiding or pagehide; it never resumes playback automatically. Current time remains on an existing media element, while a full document reload starts a new element. site/data/motion-contracts.json specifies each local transition’s owner, endpoints, duration, easing, delay and interruption rule.
Verification budgets and browser boundary
These are local acceptance budgets, not measured production service levels. A result is verified only when its named evidence contains a completed run. An owner is a role responsible for closing a failure; the package does not invent an assigned Raycast employee.
| Budget | Threshold | Owner and verification |
|---|---|---|
| Network/privacy | 0 automatic third-party requests; 0 POST/PUT/PATCH/DELETE; 0 user-data persistence writes | Reference maintainer; browser request log plus storage/API interception for every flow. |
| Shared assets | Per-entry loaded CSS ≤100 KiB; JS ≤50 KiB; Latin/technical fonts ≤150 KiB combined; supplemental script fonts load only when needed | Reference maintainer; file sizes and resource records. Source archives do not count as public runtime assets. |
| Images/media | First-viewport images ≤1,500 KiB combined; each below-fold evidence image ≤1,500 KiB; lazy loading below fold; no autoplay | Asset maintainer; dimensions, file sizes and browser waterfall. |
| Collection work | ≤500 incoming records; ≤40 search links per visible page; ≤80 article blocks; ≤5 attachment descriptors | Reference maintainer; schema/reducer tests and DOM counts. |
| Filter response | 500 rows, 20 changes: p95 ≤100 ms and no task >200 ms on the recorded host | Verifier; retain timings, data, browser and viewport. This is not a real-user INP claim. |
| Initial rendering | Cold local LCP ≤2,500 ms, CLS ≤0.1 at 390×844 and 1440×1000, three runs | Verifier; PerformanceObserver with cache disabled and raw results. Do not claim a pass from file size alone. |
| Degraded network | 150 ms latency, 250,000 B/s download, 125,000 B/s upload, 4× CPU slowdown: ready ≤8 s, LCP ≤6 s and CLS ≤0.1 at 390 and 1440 px | Verifier; verify-operational.cjs records actual Chromium emulation. No physical-device or real-user claim. |
| Retained memory | After warming 500 rows, 60 filter cycles add ≤8 MiB collected heap, retain the same row count and display at most 30 rows | Verifier; recorded CDP heap/DOM counters and explicit garbage collection, not a universal leak claim. |
| Accessibility | Local WCAG 2.2 AA target; no critical/serious automated findings; normal text 4.5:1, large text and non-text controls/focus 3:1 | Accessibility reviewer; contrast calculation, browser probes and manual keyboard inspection. |
| Targets/reflow | At least 24×24 CSS px or a recorded spacing exception; coarse action buttons (including small), icon/copy/search/menu controls at least 44×44; fine-pointer button sizes remain 36px default, 28px small and 44px large; no essential-content clipping at 320 px, 200% text or 400% zoom | Accessibility reviewer; bounding boxes, reflow screenshots and focus traversal. |
| Motion/modes | Reduced motion removes nonessential transforms/animation; forced colors retains controls and focus; print keeps prose usable | Verifier; emulated preferences and actual output inspection. |
The overview caption uses a 12% grey-900 scrim over the existing decorative background gradients. This is a local contrast correction; it is not attributed to the captured product. evidence/verification/verify-hero-contrast.cjs compares the normal caption with a transparent-glyph background capture while retaining its text shadow. Run it through the Playwright wrapper with --out set to a new evidence directory; --base selects the served guide and --browser selects the recorded engine. The default matrix covers eight viewport widths, expanded copy, and 200% caption text. Empty pixel samples, ratios below 4.5:1, horizontal overflow, page errors, or changing input bytes fail the check.
The homepage preloads a 331,084-byte display derivative to reduce the hero transfer by 40.55%. It preserves the 1200×967 dimensions and uses WebP near-lossless setting 40. Compared with the source PNG, the measured maximum error is 4 per 8-bit RGB channel, mean absolute error is 0.409834, and full-frame SSIM is 0.992960. This is a local packaging choice. The lossless WebP and source PNG remain available; the display derivation record records hashes and measurements. Cold and degraded-network acceptance follows actual retained executions. Reduced image bytes do not establish a bound on the intermittent document-delivery stalls observed in earlier tests.
The original source measurement boundary is installed Chromium driven by Playwright. Local verification also records its named Firefox or WebKit engine when actually executed. The implementation requires native dialog, ES modules, fetch, Unicode normalization, grid, :has() and dynamic viewport units. Firefox 153 and Playwright WebKit 26.5 have now launched with task-local library recovery; their actual page and control results are retained under evidence/verification/cross-browser-* and the final verification reports. A launch is not a behavior pass. WebKit on Linux does not establish branded Safari or physical-device equivalence. Record browser versions rather than “all modern browsers”.
Keyboard/DOM/ARIA automation can verify names, roles, focus, state and relationships. It does not substitute for testing with an actual screen reader or representative disabled users. Manual VoiceOver/Safari and NVDA/Firefox checks remain not-run until executed on those platforms. A future report must name device, browser, assistive technology, task, result, failures and owner. Do not turn that limitation into a claim of production accessibility certification.
The data suite independently checks schema shapes, real UTC dates, positive integer money, references, actual asset hashes, text preservation, unsafe URLs, sparse/malformed data, duplicate revisions, request ordering, stale thresholds, offline preservation and permission clearance. Its result file records all input hashes. Browser geometry, responsive, interaction, network, contrast and live deployment verification require their own evidence.
Contribution, versioning and recovery
The original local contract is 1.0.0; the additive public-family schemas are 1.1.0, independent of the Raycast app and SDK versions. Frozen junior artifacts retain the version they received. A patch corrects compatible copy, evidence links or tokens. A minor adds an optional field with a fallback, a variant or a page while preserving old consumers. A major renames/removes fields, changes defaults, routes, persistence, permission semantics or data meaning. Required new fields are a major change once a version has been released.
Before changing a shared rule, identify the independent inventory row, affected occurrences and public source. Add the data/state example and acceptance assertion, change the authored implementation, rebuild, run data and relevant browser checks, then compare 390/768/1440/1920 px captures. Review geometry and provenance with a second context/person. New controls need anatomy, parts, exact geometry, event/default/disabled behavior, native semantics, keyboard handling, content extremes, source links and an owner. Copying a similar-looking component without an API/state record is insufficient.
There is no end-user data migration. Authoring JSON migrations run deterministically in a local branch, preserve IDs or keep redirect/legacy anchors, regenerate output and compare old/new manifests. Reject an unsupported major schema version instead of coercing it. For the example rename title → name, convert the authored JSON, remove title, validate all records, rebuild search/index pages and run deep-link tests; accepting both indefinitely is not the migration.
No remote feature-flag or experimentation provider is installed. The mode select and scenario controls are explicit local specimens. They cannot enable private operations. Introduce a new contract version if a future feature needs persistent settings, remote data or experimentation. A release kill switch is removal of a faulty static entry point or rollback to the prior artifact, with its evidence and assessment restored together.
Record an exception in ITERATION-LOG.md with ID, need, affected files, owner, source, user consequence, review date and a removal test. Recheck public sources after 30 days or observed drift; preserve the old capture date until new evidence exists. A date-only edit does not make evidence fresh. Keep deprecation warnings and aliases for one documented minor release before removing a public local anchor or API in a major version.
Rollback means republishing the last verified site/ artifact under the same private deployment name and restoring its matching contract, fixtures and source manifests. Rerun link/navigation checks, record the rollback and invalidate scores from the replaced version. Local/live bytes and the assessment must agree. Publishing and independent benchmark passage are separate operations.
The four handoff tasks cover a high-use extension-card change, a Notes feature page with pricing examples, a reusable dated-snapshot notice and a narrow RTL collection with delayed/duplicate/offline/permission responses. Each brief names files, component IDs, tokens, fixtures, sequence and observable assertions. An independent context-limited implementer executed all four tasks against the retained frozen input; all 24 stage records and sealed outputs are under evidence/junior/. Later integration reruns are separately attributed and do not alter those original records.
Content, typography and secondary browser checks
site/data/content-contracts.json provides vocabulary for every public object, fourteen message contracts, variable rules and five-locale formatting fixtures. content-model.mjs preserves canonical identifiers, rejects invalid count values and uses locale-aware plural, date, amount and stable numeric collation. Synthetic translations and full-page pseudo/RTL stress tests do not imply human translation review.
site/data/typography-roles.json makes all fourteen local role fields explicit. Numeric local replacements for three source normal line heights are labeled as reconstructions. Original computed declarations and route-specific geometry remain in the evidence.
verify-review-regressions.cjs, verify-composition-controls.cjs, verify-collection-pages.cjs and verify-content.cjs take a base URL and an output directory. REFERENCE_BROWSER=firefox selects the installed Firefox; WebKit can use the task-local launcher in evidence/tooling/webkit-userland.sh with its explicitly required bundle, library and registry paths. Official Ubuntu download/extraction receipts are retained in that directory. The recovery uses task-local libraries and official Playwright engine bundles; it does not modify system packages or the shared Chromium runtime. Each final run records actual source hashes before and after execution; changing a tested implementation invalidates the corresponding result.
The Store example has a bounded thirty-card page with a stable total count, previous/next actions and page_store-demo URL state. Query/category changes reset its page; other small catalogs keep their existing unpaginated behavior. verify-expanded-pages.cjs retains compressed content snapshots for every guide page under at least 30% pseudo expansion and RTL reflow.
Public-family composition implementation
The additive family reference has 47 route recipes, 14 inventoried object bindings, 11 public flow bindings and explicit ownership for the 120 inventoried component IDs. These counts are mappings. They do not establish pixel equivalence or complete coverage of every source route instance. The executable authority is reference-data/remediation/family-contracts.mjs, family-render.mjs and build-family-reference.mjs; site/data/family-contracts.json is the generated map. Match each ID to the assertions and source hashes in evidence/verification/family-remediation/, then read the separate authored source comparisons before assigning completion.
The builder emits 47 sibling family-*.html compositions plus family-reference.html and family-objects.html. Root integration calls await buildFamilyReference() from build-site.mjs. Run the existing root command from the repository directory:
node designs/raycast/reference-data/build-site.mjs --standalone-report evidence/verification/remediation-round5/standalone-icons/results.json
python3 -m http.server 4178 --directory designs/raycast/site
node designs/raycast/evidence/verification/family-remediation/data-tests.mjs
.agents/skills/design-research/scripts/run-playwright.sh designs/raycast/evidence/verification/family-remediation/browser-tests.cjs http://127.0.0.1:4178/
.agents/skills/design-research/scripts/run-playwright.sh designs/raycast/evidence/verification/family-remediation/anatomy-tests.cjs http://127.0.0.1:4178/node designs/raycast/reference-data/remediation/build-family-reference.mjs is the isolated family build. Regenerate before testing; do not rebuild while a verifier is collecting hashes. Node 24.13.1 was used. All schemas are reconstructed local contracts, including Publisher, AIModel, ScriptedTask/ToolGroup/ToolCall, Release, Story, ExtensionTemplate, AccountEntryAttempt, JobOpening and KeyboardProduct. Existing Extension, Plan, Article, Asset and PublicFeedback retain their original authority boundary. site/data/family-fixtures.json contains fictional authoring records; actual public identity/media observations are separately identified in the rendered examples.
| Concern | Authority and exact boundary |
|---|---|
| Schemas and relationships | reference-data/remediation/object-contracts.mjs adds strict fields to implementation-contract.json; family-model.mjs enforces cross-record joins and lifecycle. Unknown properties, unresolved IDs and unsafe destinations are rejected. The model never fetches. |
| Fixture generation | family-fixtures.mjs generates the named synthetic records. history-shapes.mjs retains only the 74 source entries’ format/count metadata, extracted by extract-history-shapes.py from the pinned public HTML. It contains no copied release prose. |
| Browser code | site/assets/family-reference.mjs owns shared navigation, search, tabs, pricing, collections, newsletters and gallery movement. It awaits family-ai.mjs for AI/composer/provider controls, family-account-forms.mjs for feedback/account forms, and extension-gallery-viewer.mjs on the extension gallery. Keep all sibling modules when copying a page. |
| Browser model | family-ui-model.mjs is generated from the browser-needed prefix of the pure model and shared by the optional controllers. Node-only ingestion and relation validation remain in family-model.mjs. Never edit the generated prefix directly. |
| Styles and fonts | family-reference.css owns family layouts. family-base.css is the exact shared font/token/reset prefix generated from reference.css before .navbar-wrap; the full guide’s component rules are omitted. fallback-fonts.css supplies explicitly local Japanese/Devanagari fallback faces. English source geometry still uses Inter; missing-script fallback is not a production typography claim. |
| Source anatomy | source-authored-hierarchy.json holds pinned public trees/computed parts for history, template and AI, with raw capture pointers. source-component-metrics.json is a bounded lookup and explicitly is not the complete geometry denominator. |
| Diagrams | diagram-contracts.json and site/data/family-diagrams.json define data, units, scales, node/edge order, accessible tables/text and fallback behavior for Focus, developer and automation diagrams. Synthetic series/topology remain distinct from source graphics. |
The family entry publishes window.familyReference after its selected controllers and URL state have finished initializing. The document root exposes data-family-reference-ready="loading|true|failed". An optional-module failure leaves the ready object absent, preserves the current draft DOM, blocks unhandled form submission and shows “Reload page (clears local draft)”. A reload deliberately starts fresh. Per-page JavaScript budgets count the actual uncompressed response bodies of the loaded modules; the verifier may conservatively pin other optional modules without treating them as downloaded bytes. A new composition that combines optional controllers needs a fresh budget check; passing the existing pages does not establish a bound for every possible combination.
service-contracts.mjs binds the four entries in declared-scope.json#/applicableServiceProfiles to exact family, object and flow IDs: SERVICE-1 covers public product education, SERVICE-2 the developer/catalog ecosystem, SERVICE-3 plans and account entry, and SERVICE-4 editorial/support entry. Overlapping membership is explicit. Each browser service assertion requires every listed family at all four widths, current strict schema/fixture/relationship checks, actual object representation and every declared public flow assertion. A service execution pass does not close a missing source comparison.
The Store composition uses q, category, platform, order and page. Query matching normalizes NFKD, removes Unicode combining marks, lowercases in English and compares substrings across name, summary, publisher and tags; categories and platforms use exact known values. order=popular sorts descending downloads with null last and ID ties; order=recent sorts descending UTC time with ID ties. Six cards form a page. A changed query/filter resets page to one. Unknown values canonicalize to defaults, duplicate recognized query keys collapse on write, unrelated keys and the fragment remain. Input work is scheduled once per animation frame. Clear filters removes all four filter values, resets page and focuses the query. No filter writes browser storage.
Family search is a 47-entry embedded index of family names, route filenames and composition keywords. Command/Ctrl+K opens its native dialog and focuses the query. It shows at most 20 safe sibling links and announces the full matching count. The query remains only in the current dialog DOM. First Escape closes without erasing it and returns focus; no global family search request, compressed or otherwise, is issued.
Extension sections use section=overview|commands|history with native roving tabs, ArrowLeft/Right and Home/End; Overview removes the parameter. Optional extension=<id> applies a synthetic Extension plus matching ExtensionDetail/Publisher, and an unknown ID shows an unavailable state with a directory return. Omitting the ID selects the explicitly labelled captured Linear instance. Publisher similarly uses publisher=<id> for fictional ready/unavailable/RTL-empty fixtures and no parameter for the public Linear example. Neither selection grants installation permission.
The captured Linear screenshot strip contains seven images in their original order. At 390 and 1440px each slide is 286px wide with a 6px gap; the first Next action advances 292px, and Previous returns to zero. The controller derives reachable positions from the rendered slide starts and scroll extent, follows manual scrolling and clamps both ends. The 320px layout narrows a slide to its available container. The strip uses ArrowLeft/Right and Home/End.
Activating a screenshot opens the full-size viewer. The captured centered image is 70vw, adjacent previews are 60vw, ArrowLeft/Right and preview buttons move through the same seven images, and Escape, Close or the backdrop dismiss it. The local native dialog adds named controls, bounded Tab navigation, a live count, scroll locking and restoration of focus to the triggering screenshot. On coarse pointers, transparent hit areas extend the partly clipped adjacent previews to at least 44px without changing the source image geometry. Close is immediate; the source exit fade is not reproduced. reference-data/remediation/extension-gallery-viewer.json binds the observed behavior, these additions and the derived image assets.
Publisher actions retain the captured 62px grid column and the intrinsic dimensions of the short “Install” and “Share” labels. A longer label may use the card’s existing 20px outer gutter before wrapping, including words with no natural break. The max-width, flex-shrink, white-space and overflow-wrap rules are an explicit accessibility adaptation, not an observed source variant. The isolated before/after diagnosis preserves every default publisher descendant box at 390 and 1440px. publisher-reflow-tests.cjs checks the actual implementation at 320/390/768/1440px with expanded LTR/RTL copy and unbroken labels; its current result and source hashes determine whether a later build passes.
Changelog list uses platform=macos|windows|ios and page with two Release records per slice. Platform and pagination push history; platform changes reset the page, and Back/Forward restores the slice. A detail uses release=<id>, shows only that record and returns to its platform. Unknown release identity shows recovery, not another release. AI task=<id> switches its fixture thread and project selection, closes tool groups and preserves the single in-memory composer draft. Unknown tasks remain unavailable until a listed scenario is selected. Model provider and job department filters, screenshots, pricing tier/cadence and disclosure state are document-local. Template thumbnails replace the primary image; Copy copies the displayed scaffold command as inert text. No command runs in a shell.
Pricing resolves Plan.featureIds → Feature.id whenever cadence or tier changes. Each visible item has data-fr-feature-id and shows the feature title, entitlement label and availability note; the snapshot date comes from that same Plan. Pro, Plus and Max intentionally share the same two unverified feature records in these fixtures. Selecting a tier changes its amount and identity without inventing different eligibility. Missing feature joins fail authoring validation; damaged browser data falls back to “Feature not supplied” with unverified availability. Account-entry forms expose the retained public destinations https://www.raycast.com/terms-of-service and https://www.raycast.com/privacy beside their local boundary explanation. These links do not simulate legal consent or authentication.
The source history renderer owns the shared 20px auto grid and 16px gap; each version uses display:contents, a 20px icon/timeline column and heading/date plus body. The 74 synthetic entries preserve 64 list bodies, nine paragraphs and one heading-only entry. Source prose, inline code/links, exact wrapping and total height are not equivalent; the public phone capture has a min-content overflow that is retained in source evidence. Template owns the desktop 296px sidebar/834px content/10px gap; below 840px its columns stack with 46px gap, while the sidebar retains 24px inline padding. The large image precedes two scrollable thumbnail controls, then instructions and prose. Native thumbnail buttons, a named copy target and a safer 320px identity layout are explicit accessibility adaptations.
The AI default scene preserves the 1020px intrinsic frame, 280px sidebar, 740px chat and 708px tool groups. At 390px its 350px viewport scales the 660px phone frame by 350/1020; this marketing scene is inert on phones as the public source was. “Use readable interaction view” operates the same DOM at readable size and enables normal keyboard controls; this is a separate authored layout, not source mobile equivalence. Tool summaries have glyph stack, combined label/count and chevron; open groups contain compact icon/label calls with completion/permission state. Readable text colors and 44px disclosure targets intentionally differ from some source values. No model, integration, clipboard-reading or microphone operation occurs. The stage observes width changes and schedules one animation-frame update; its derived height changes do not schedule another observer write. Reduced-motion disables document-level smooth scrolling as well as descendant transitions.
Family feedback uses the same FeedbackDraft adapter as the guide, with general valid email, Unicode code-point limits, at most five native file descriptors and 20 MiB per file. Hidden category controls are disabled while retaining their draft selection. Validation is immediate on this family page; the guide’s separately labelled 450ms/loading/error/offline specimen remains its own state demonstration. The family form uses method="dialog", never POSTs, and retains over-limit text for correction. Synthetic PublicFeedback fixtures still accept only @example.com; this is an authoring safeguard, not a restriction on a transient UI draft.
The only family event history is the last 100 {name,id,at} records available through window.familyReference.getEvents(). IDs are fixed local control/fixture identifiers and time is monotonic milliseconds since document navigation. Do not add email, query, message, password, copied text or filenames. The buffer is discarded on navigation and is never stored or sent. Source destinations use the fixed HTTPS host allowlist in safePublicHref, reject credentials/ports/control characters/encoded slash or backslash, and require a labelled user action. Native install, organization entry, purchase and authentication remain public handoffs. Shared media-lifecycle.mjs pauses audio/video on hidden/pagehide and never resumes automatically.
reconcileRecords validates before ingestion, deep-copies accepted records, compares objects independent of property order while preserving array order, and keeps the highest valid revision. Conflicting content at the same highest revision is quarantined; a later higher revision resolves the visible identity while the rejection audit remains. A dated snapshot older than 24 hours is stale. Empty, partial, stale and error do not imply a service response; the adapter processes bundled inputs. The recovery-state lab is explicitly a presentation simulation. Browser tests, schema tests and source comparisons have separate pass/fail records and before/after hashes. A failed or changed input remains a failure until actually rerun.
Remaining fidelity boundaries are concrete: many of the 47 route families have authored pattern/interaction tests but no complete source comparison of every component, state and route member; their metadata cannot be used as Complete evidence. Synthetic article, customer, release and model content demonstrates typed structures and access states, not current product claims. Chart series, animation phases, private API behavior, actual screen-reader use and physical native clients require their own evidence. Review the denominator reconciliation for the unresolved per-ID obligations; do not average those gaps away using a mapping count.
The extension detail navigation follows the retained ExtensionPage__navigation and PillLink geometry in evidence/inventory/geometry-closure/linear-commands-{390,1440}.json (/geometry/153, with the three pills matched by label at /geometry/24, /geometry/25, and /geometry/190). Native buttons keep the authored roving-tab, selection, and URL behavior. They wrap on narrow screens according to the captured pill widths. Compatibility uses the captured 16-pixel macOS and Windows SVG paths, 8-pixel row gap, and 12-pixel list gap from /geometry/269–/geometry/273; only fixed path data from platformPresentation() can become SVG. Fixture-selected extension pages update the platform labels from that Extension record. These labels do not verify a user's installed operating system or entitlement.
The publisher layout owns its decorative background, sidebar, and collection. Its source breakpoint is 1064 pixels: narrow layouts use one column with no additional row gap; desktop uses a 224-pixel sidebar, a 40-pixel gap, and the remaining collection width. The retained source is evidence/capture-more/pages/linear-390.json /measurements/14 and linear-1440-lower.json /measurements/13. The readable #aaa joined-date text deliberately differs from the captured white at 40% opacity. The existing long-label wrap is also an authored accessibility adaptation. Neither difference is hidden by a wider source-comparison tolerance. Publisher wrapping regression checks compare row dimensions and row-relative child positions, while the separate source comparator owns the corrected outer layout and background.
The sign-in contract disclosure includes a nested “Captured hidden email-notice copy” example. Its text comes from evidence/inventory/boundary/signin-1440.html, p.page-module___qf-sa__notice.page-module___qf-sa__invisible, delivered by the public sign-in page. That copy was hidden in the retained source and was not observed as an email-delivery outcome. Opening the local disclosure sends no email and establishes no session. STATE-auth-hidden belongs to this explicit reading example; password mode changes and tokenless confirmation do not prove it.
Below 360 pixels, the extension tablist has min-width: 0. This local reflow guard lets the native pills use the available width; it does not change their padding, label text, roving keyboard behavior, or the measured 390/1440-pixel source geometry. The original 320-pixel failure and browser-only proposal are retained in evidence/verification/family-remediation/tabs-reflow-diagnosis.json. Modal keyboard verification permits the browser's own chrome to receive focus between cycles: every focused element inside the document must remain in the modal. The recorded diagnostic distinguishes document.hasFocus() === false with BODY from actual focus on an underlying page control.