AmoleoFamily

Foundations

Live order — enforced by check-lockup.mjs

1 Pets
2 Connections
3 Rissbrook
4 Accounts

Pending — registered, not yet in any live footer

5 Todo
6 Editions
7 Upnext
8 Collections
9 Reviews
10 Worldbook
11 Health

Tracked position for when each is ready, not enforced anywhere yet. Promote one with node tools/promote-to-lockup.mjs --key <key> once it's actually going to appear in every live footer — that's also the moment every currently-passing repo needs its own footer updated to match.

Registered surfaces

SurfaceNotes
Amoleo-WebsiteThe four product cards on the front page — each an
with its own wordmark, screenshot and blurb.
Amoleo-WebsiteThe APPS list scripts/make-og.py reads when it renders the family names along the bottom of the OG share card (assets/og.png).

Product order — the one sequence the family lists in

Pets, Connections, Rissbrook, Accounts. Oldest first, Accounts last — it is the infrastructure the other three will eventually sit on, not a product launched alongside them, so it reads as what it is rather than as a fourth peer. This order is not a style choice re-litigated per surface; it is fixed, and every place that lists more than one product has to use it.

The order is recorded once, in tools/lockup.json's apps array — the footer lockup's own spec file, reused here rather than restated. That file already had to answer "what order do the products go in" for the footer; giving that answer a second home would be exactly the copy-and-drift this workspace exists to prevent. If the order ever changes, lockup.json is the one place that changes.

This document, and tools/check-product-order.mjs, cover what check-lockup.mjs doesn't: surfaces that aren't the footer. The footer's own order was already enforced — every repo's lockup is one element check-lockup.mjs reads directly. The order silently stopped being enforced the moment a second surface listed all four products, because nothing was watching that surface. That is exactly how Website's front-page cards and make-og.py's OG-image generator got built correctly, by hand, matching the footer — and would drift the same quiet way the brand colours and the wordmark did if a future edit reordered one without anyone noticing, because neither file is the footer and neither was covered by the footer's checker.


1. Known surfaces

Surface Repo File Checked by
Footer lockup every repo (per repo — see family-footer.md) check-lockup.mjs (already existed)
Front-page product cards Amoleo-Website index.html check-product-order.mjs
OG-image generator's family list Amoleo-Website scripts/make-og.py check-product-order.mjs

The second and third rows are recorded in tools/product-order-surfaces.json, which holds only where to look, not the order itself — same relationship header.json has to wordmark.json's base size. Each entry is a file and a regular expression that captures a product key each time the surface names one; the checker reads the keys out in the order they appear and compares that against lockup.json's order, filtered down to whichever products the surface actually mentions.

When you build a new place that lists more than one product — a nav menu, a sitemap, a "featured products" block, a future Accounts dashboard — add it to product-order-surfaces.json in the same commit. An unlisted surface is invisible to the checker in exactly the way the front-page cards and the OG generator were before this file existed.

A surface that only ever shows one product (a product's own header, its own OG card, its own footer's self-entry) has nothing to order and does not belong in this file — see family-wordmark.md §8: "It isn't expected to appear in Pets, Connections, or Rissbrook, each of which only ever talks about itself." The same logic applies here.


2. Running the checker

node tools/check-product-order.mjs

For each registered surface: read the file, extract every product key the surface's pattern matches, in the order they appear, and compare against the canonical order. A surface that lists three of the four products is fine as long as those three are in the right relative order — the check is about sequence, not completeness (a nav that only links Pets and Connections isn't wrong for omitting Rissbrook; it would be wrong for listing them the other way around).


3. What it does not check

Generated from docs/family-product-order.md + tools/lockup.json + tools/product-order-surfaces.json. Edit there and re-run npm run build in docs-site-src/ — never hand-edit a page.