open-standards/aac/aac-rs/tools/pagesets/DESIGN-phrases-common.md
Transaction Science 8306784d39 aac: the reference app is the AAC Reference App, no longer "Express"
"Express" is also TD Snap's page-set name in the same field. The standard's
reference app is now called the AAC Reference App: READMEs, crate docs,
tool docs and the page-set design notes (which now say it was renamed). Its
default title, without AAC_APP_TITLE, and its manifest name are
"AAC — reference app". Code identifiers are unchanged.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-10 22:42:12 -04:00

31 KiB
Raw Permalink Blame History

Phrase page sets: what they share

Four page sets for aac.aurasense.ai/app (the AAC Reference App, built on the open AAC standard) and for any app that reads Open Board Format (OBF):

Set File For Design
Adult conversation adult.obz adults whose talking has changed: aphasia, ALS/MND, primary progressive aphasia, brain injury, Parkinson's DESIGN-adult.md
Intent first (12, 20, 40) intent-12.obz, intent-20.obz, intent-40.obz anyone who starts from what they want to do; also a printed book a partner reads from DESIGN-intent.md
Themed phrases themes.obz quick everyday messages, one 6 × 3 page per theme DESIGN-themes.md
First switches and messages emergent.obz first communication and first switch use DESIGN-emergent.md

This page covers what the four have in common: how they are written and built, the OBF they produce (and the ext_aurasense_* extensions they use or propose), how their translations were checked, their licences, how the app should offer them, and the decisions they need from the founder.

The design follows the gap analysis of 2026-10-04 (REPORT.md on the model-library drive, Part 1 and §1.1, §2.2, §2.7, §2.10–2.12, §4 items 8, 10, 13, 14 and §5). Every word, layout and name here is ours. No proprietary page set was copied, and none is named on any board: the generator refuses a board that names one (see Guards below).

Sources and build

aac-rs/tools/pagesets/phrases/
  sources/adult.yaml  intent.yaml  themes.yaml  emergent.yaml   the sets, by hand
  build.py              validate the sources; build the packages and catalogue
  review.py             the two-reader translation check, round by round
  translations/<lang>.json        every text's translation, status and evidence
  translations/review/<lang>/round<N>/   each round's record (see Languages)
  reports/sets.md  symbols.md  translation-status.md   review aids, generated, committed
  LICENSE.md            CC BY-SA 4.0 for the sources and every package built from them
aac-rs/crates/aac-core/tests/pagesets_phrases.rs     the import test

The packages are generated, not committed. The site build makes them:

cd aac-rs/tools/pagesets/phrases
python3 build.py --check                         # fail on bad sources, a non-reproducible build or stale reports
python3 build.py --out "$SITE/pagesets/phrases" --hash-names

--out DIR writes DIR/<set>.obz (English, with the pictures and every agreed translation), DIR/<lang>/<set>.obz (one language; <set>.f.obz and <set>.m.obz where the speaker's gender changes the words), DIR/index.json (the catalogue: families, sets, sizes, descriptions, licence, each file with its size, sha256 and how many of its cells are still in English, and each language's status) and DIR/LICENSE.md. --hash-names names packages <set>.<sha256-12>.obz for a cache that keeps files for hours. --check [--out DIR] builds twice in memory and fails if the bytes differ, if reports/ is stale, or (with --out) if DIR differs from a fresh build. --reports rewrites reports/; --strings writes work/strings.json for translators. The interface matches the core page sets' tools/pagesets/build.py (--check, an output directory, deterministic output), so one catalogue can list both; this generator's index.json is self-describing (version, generator) for that.

Today a full build is 99 packages, 28 MB, of which the six English packages (with pictures) are 5 MB and each language package 100–450 KB.

Python 3.11 or later with PyYAML. The build reads only the app's own symbol index (crates/aac-core/src/symbols/index.json) and sprites (crates/aac-web/public/symbols/); it never touches the network, and the same sources always give the same bytes (UUIDv5 ids, a fixed zip date, sorted output).

The source format

A source file has set (name, description, version, licence, which symbol sets it may draw from, the root board), a palette of named colours, cells (named cells used as $name), optional frames (cells placed on every board of the set), and boards (or, for the intent-first set, sizes and sections). A board is laid out by rows, each a list of cells from left to right, so the layout reads as it looks. A cell is:

Written as Means
"I'm tired." a message: shown and said
$yes the named cell yes
~ an empty place, kept empty (SPEC §2: a blank keeps the grid)
{label, say} shown label, said say
{add: "I want to"} words added to the message without being said (a sentence starter)
{label, go: board} a link; with say too, the words are added and then the board opens
{label, do: backspace | clear | speak} a message-bar command
symbol: concept the picture: a concept of the app's symbol index (it must exist)
want_symbol: concept a picture we want but the index does not have (listed in reports/symbols.md)
fill: {words, photo, recording, hint} a template for the person to complete
seq: {lines, order, at_end, reset_after_minutes} each press says the next line
effect: sparkle | bounce | confetti a short animation with the words
src: universal-core where the words came from, if not written for this project
note: context for translators (not written into the packages)

A board may say popup: true (it closes after a choice), speak_only: true (its cells speak and never build a message), parent: (where Back goes; otherwise the first board that links to it) and description: (a note to the partner). YAML 1.1's other booleans are switched off: yes, no, on and off are words.

Guards

build.py refuses to build when:

  • a cell is outside its grid, two cells share a place, or a link leads to a board that does not exist;
  • a board cannot be reached from the root;
  • a symbol concept is not in the app's index, or not in a set the page set may use (the adult set uses pictograms only: Mulberry, then OpenMoji, no Bliss);
  • a sequence has fewer than two lines, names a cell that does not speak, or has an unknown order or ending;
  • any text names a proprietary product (PROPRIETARY_NAMES: PODD, TD Snap, Proloquo, LAMP, Unity, Minspeak, Gateway, WordPower, TouchChat, Lingraphica, Grid 3, BIGmack, Step-by-Step, PECS, Boardmaker, PCS, …);
  • any text reads as a medical claim (CLAIM_WORDS: diagnose, treatment, therapy, cure, heal, rehabilitate, recover, clinically, prevents, …). The sets are for wellness, research and clinical-trial use; they are not a medical device.

The OBF the generator writes

Each package is a .obz: a zip, stored without compression (what the app's own importer reads directly), of manifest.json, boards/<uuid>.obf and, in the English package, images/<symbol>.svg. Ids are UUIDv5 of the set, board and position, so a rebuilt board keeps its ids, and every language's package has the same board and cell ids in the same places (the test checks this: changing language never moves a word, SPEC §3).

Standard OBF fields: format, id, locale, name, description_html, license, grid (rows, columns, order), buttons (id, label, vocalization, label_locale, vocalization_locale, load_board, action, image_id, background_color, border_color, translations), images (id, content_type, width, height, path, symbol, license) and sounds.

Extensions the app already reads or writes

Field Where Meaning
ext_aurasense_provenance board, button where the words came from: source_label / source_vocalization (the stored words), words_locale (the words are in this language, kept exactly as written, never glossed: the app's own-words cell), translation ("agreed by two model readers; native review pending", or "pending: shown and said in English"), english (the English source), source (file, board and position in the sources), symbol_wanted, words_source
ext_aurasense_locked board, button false: the person may change everything
ext_aurasense_text_color button the text colour
ext_aurasense_action: "buffer" button add the words to the message without saying them (sentence starters)
ext_aurasense_symbol button the picture, as a concept of the symbol index (the app draws it in the person's chosen set and skin tone; Track B reads and writes it)
images[].symbol + license image the symbol set and file, with the set's licence, attribution and conditions

Extensions these sets add

A client that does not know them still works: each falls back to plain OBF. The App column is the state on aac/pagesets-phrases: acts on it (aac_core::behaviours, aac-web sequences.rs, behaviours.rs, actions.rs, scan.rs, switches.rs, pointing.rs), or kept (on the cell or board, written back on export, and named once in the import's warning: "These boards use features this version can't do yet: … They are kept.").

Field Where What the app does Fallback App
ext_aurasense_sequence button each press says the next line; full behaviour in DESIGN-emergent.md vocalization is the first line acts on it
ext_aurasense_effect button a short visual effect with the words (DESIGN-emergent.md) none kept ("animations")
ext_aurasense_behaviour.after_choice: "return" board a popup: after a cell that says or adds words, go back to the board that opened this one stays; a Back or Start cell is on the page acts on it
ext_aurasense_behaviour.message: "speak_only" board its cells speak at once and are never added to the message words are added too acts on it
ext_aurasense_link_says: "I want" button with load_board add these words to the message as a speaking cell would, then open the board (the words themselves, as well as in vocalization: a reader that makes the button a link keeps no vocalization, but keeps this field) the link opens; the words are not added acts on it
ext_aurasense_fill_in button {words, photo, recording, hint}: a template cell; Edit mode marks it "to fill in" and lists every such cell after the set is added; the hint is shown in the cell editor; editing the cell drops the mark the cell says its words (… is a pause) kept ("cells to fill in")
ext_aurasense_book.page board page number in a printed book printing numbers pages itself kept quietly (the app prints books and numbers them itself)
ext_aurasense_book_goto button with load_board the page it links to, printed as "→ 12" none kept quietly (same)
ext_aurasense_speaker_forms button, in a language's f/m packages {f: {label, vocalization, lines}, m: {…}} for a word that changes with who says it: the app puts the person's form there, or leaves the word out while they would rather not say the package's own form acts on it
translations.<lang>.ext_aurasense_speaker_forms button {f: {label, vocalization}, m: {…}} where the speaker's gender changes the words that language's words are absent: English
translations.<lang>.ext_aurasense_sequence_lines button a sequence's lines in that language English lines
manifest.ext_aurasense_page_set manifest key, name, version, locale, speaker_forms none

The importer defect, fixed. aac_core::obf used to accept every ext_aurasense_* field silently and keep none it did not know, so a sequence or popup was lost without a word (SPEC §8 forbids it). It now keeps every field it does not map — ext_aurasense_* or any other — on Cell::extra / Board::extra, writes them back on export, and adds one warning per import naming, in plain words, the features it keeps but does not act on. A few fields with no meaning for the app (url, data_url, description, description_html, default_layout, default_locale, background, and the position fields top, left, width, height) are kept without a warning. The test checks the warning, and that sequences, links that say words and board behaviours survive an import.

SPEC text (draft, after 0.2.0)

Approved and now in aac/SPEC.md (§2.2, §2.3, §2.4, §5.9 and the §8 addition, with the summary under "Proposed (draft, after 0.2.0)"):

§2.2 Sequences (proposed). A cell MAY carry a sequence: an ordered list of two or more lines, an order (in_order or shuffle), what happens after the last line (start_again or stay), whether the lines are added to the message (default: not), and an optional idle time after which it starts again. Each activation of the cell says the next line. A line MAY name another cell of the same board, whose current words (and recording) it then says. Where the next line is kept is the person's state, not the board's: using a sequence MUST NOT change the board. A client that cannot play a sequence MUST say the cell's own words (its first line) and MUST keep the sequence when it saves the board. Undo after a line MUST step the sequence back. A press during a line MUST be honoured (the person sets the pace); the hold and release times of §5 still apply.

§2.3 Board behaviours (proposed). A board MAY declare that it closes after a choice (a popup) or that it speaks without building a message. After a cell of a popup that says or adds words is chosen, a client MUST return to the board that opened it (a popup's continuation pages count as the popup). The person MUST be able to turn popups off for all boards; the choice travels with their settings. This is a property of the vocabulary's design and returns to the board that opened the popup, not home: it is not the "go home after each word" option of §5.6 item 6, which stays the person's alone and, where they have chosen it, wins over a popup's return.

§2.4 Links that say words (proposed). A cell that goes to another board MAY also carry words; a client MUST add them to the message as a speaking cell would, then open the board.

§5.9 One target (proposed). When a scan has a single target — a one-cell board, with the bar and the navigation not scanned (§5.5, §5.6 let the person choose that) — every press of a switch MUST select it at once, and a touch or dwell anywhere on the board MUST select it.

§8 addition (proposed). An extension field a reader does not act on MUST be kept with the board or cell (§2) and reported once as a warning, so that a sequence, popup or other behaviour is never lost without a word.

Symbols

Pictures are chosen by concept from the app's own symbol index (472 concepts on 2026-10-05: Mulberry, OpenMoji, Bliss, all CC BY-SA 4.0), never by inventing ids. Each set says which sets it may draw from: all four use Mulberry, then OpenMoji (pictograms); none uses Bliss, which is a semantic symbol language rather than a picture, and which a person can still choose in the app (the app draws ext_aurasense_symbol in the person's own set).

Many adult concepts have no symbol yet (throat, chest, suction, frustrated, appointment, …): those cells show their words alone, and an adult may add a photo instead. reports/symbols.md lists every concept wanted and where. Adding them is a job for tools/symbols (a confident match only: a wrong picture is worse than none), after which the sources name them with symbol:.

The English packages carry the pictures (each symbol once, as images/<id>.svg, cut from the app's sprite with its set's attribution); the language packages name each symbol by concept only, which the app draws from its own sprites. That keeps each language package small (100–450 KB); a language package opened in another OBF app shows words without pictures. build.py can embed pictures in every package if that is wanted (one condition in Package.button).

Languages

English is the source. A translation is used only where two independent readers agree:

  1. Draft. A drafter (reader 1) translates each text, seeing the English and where and how it is used (review.py prepare): what a native speaker would say, short and spoken; polite address in the adult set, familiar in the emergent set; a wording that does not mark the speaker's gender wherever one is natural, and otherwise both forms (f, m) — never slash forms.
  2. Blind back-translation. A second reader, who never sees the English (review.py blind writes only the translations, with each text's role), translates the drafter's words back into English and says how they read: grammar, register, and whose gender they mark.
  3. Judge. The English, the translation and the back-translation are compared (review.py judge); "agree" only when the back-translation means what the English means, with nothing added or lost, in natural words.
  4. Merge. Agreed texts become "agreed"; the rest "disputed", with the reason (review.py merge). A disputed text goes to a second round: the drafter revises it with the reason, and a fresh blind reader checks again. What is still disputed stays in English.

The status of every text in every language is data: translations/<lang>.json (status, round, text or forms, back_translation, notes), summarised in reports/translation-status.md and in each build's index.json. Each round's record is kept under translations/review/<lang>/round<N>/: draft-input.json (what the drafter saw), draft.json, blind-input.json (what the blind reader saw: no English), back.json, verdict.json. Every reader was an AI model, so every agreed text says "agreed by two model readers; native review pending", in the translation files and in the packages' provenance. A native speaker's review is still wanted for every text.

Result (2026-10-05). 1,075 English texts; three rounds.

es fr de pt it zh ja ar hi ru
Agreed 1,075 1,075 1,075 1,075 1,075 1,075 1,074 1,074 1,075 1,075
Disputed in round 1 10 17 9 9 6 15 29 21 11 6
Texts with speaker forms 29 20 0 30 24 0 0 0 14 15

Still in English after round 3: Japanese "OK" (a feelings word; every wording offered could be heard as "so-so" or a polite "no thanks") and Arabic "I did that for … years." (one cell of the adult set's work page). What round 1 caught, among others: Spanish "Eso me pone" for the starter "That makes me" (sexual slang in Spain), "Salir" for "Going out" (reads as "Exit"), "Está demasiado alto" for "It's too loud" ("too high"); Hindi कल for both "yesterday" and "tomorrow"; Japanese requests that could be heard as about the listener ("brush/wash my…"); Russian «Мне очень неудобно» for "I'm very uncomfortable" (usually "I'm embarrassed"); Arabic الحمام unvoweled (bathroom or pigeons). The readers also showed three English texts were unclear in every language, and they were changed: "Adult home" (a care home) became "Home"; "My own card" (an ID card) became "In my own words"; three theme starters that no word on their page completed were rewritten.

Two blind readers (Spanish, Arabic) were stopped part-way by the model provider's content filter; Spanish was rerun as it was, Arabic as four readers of one part each. Neither saw the English.

A cell is shown and said in one language: if any of its texts (label, message, sequence lines) is not agreed, the whole cell stays in English (an empty translation is allowed only for a link's spoken words that the language does not need, such as the English "to"; a label is never blank), marked label_locale: "en" / vocalization_locale: "en", and its board's description_html carries a visible note, in the board's language: "Some messages on this board are still in English: their translation has not yet been agreed by two readers."

Done first: the ten largest app languages (es, fr, de, pt, it, zh, ja, ar, hi, ru). Pending (English only, listed in index.json): nl, ko, he, ur, fa, bn, ta, te, ml, mr, kn, gu, pa, th, vi, id, ms, tl, pl, uk, ro, cs, sv, da, nb, fi, sw, am, ha, yo, zu, tr, el, hu. Adding one: add it to LANGUAGES in build.py and LANGUAGE_NOTES in review.py, run the four steps (review.py prepare/blind/judge/merge), and build.

What translation cannot fix. Sentence starters and words are combined in the order the person picks them ("I want" + "to eat" + "an apple"). In languages whose word order differs — Japanese and Hindi put the verb last, German often does — the combined message is telegraphic; each language's drafter shaped the fragments to survive it (DESIGN-intent.md lists how). Phrase cells (whole messages) do not have the problem. Where a language marks a referent's gender in a label ("Friend", "Doctor", "Nurse" on the People templates), the drafters used the usual default and noted it: those are templates the person fills in and may rename.

Licences

  • The page sets (words, layouts, packages): CC BY-SA 4.0, author "AuraSense Tech Corporation and the open-standards AAC contributors" (tools/pagesets/phrases/LICENSE.md, copied into every build). ShareAlike because the English packages embed CC BY-SA symbols, and so that improvements stay open.
  • Symbols: Mulberry Symbols, OpenMoji, CC BY-SA 4.0, each image carrying its set's licence, attribution and conditions (Mulberry's symbols must stay free of charge).
  • Words: written for this project unless a cell says src:. The only borrowed list is the Universal Core vocabulary (21 single words on the 40-cell intent-first start page; CC BY 4.0 per UNC CLDS, CC BY-SA 4.0 per Project Core: treated as BY-SA, words only, no vendor symbols).
  • Nothing from PCS, SymbolStix, Widgit, METACOM, ARASAAC or Sclera; no proprietary vocabulary's words, positions, wording or names (§5 of the report). The design notes name products only to say what was not copied.

How the app should offer them

What is built on this branch. The app acts on the sets' behaviours: sequences (by touch, switch scanning with one or two switches, pointer and gaze dwell; "2 of 4" shown; Undo on the message bar's Delete; Modeling shows the next line without moving on; the partner menu's "Start the lines again" and "Back one line"; each line can be recorded in the person's own voice from the cell editor, through message banking), popups that close after a choice, speak-only boards, links that say words, one-target pages (§5.9), a large scan highlight, and the profile setting "Words about myself" (AacProfile::speaker_form; Settings → Language, shown for es, fr, pt, it, hi and ru only, never assumed). The place in each sequence is the person's (localStorage aac_sequence_places, per profile), never in the board. The English cells of a phrase package — the English package taken for a language without its own, and the cells still in English inside a language's package — are marked as English words written as they are (lang "en", pagesets::prepare): shown in English, marked, said by an English voice, never glossed word by word and never hidden. "Words about myself" can be declined ("I'd rather not say"): each word that changes with who says it is then left out, hidden in place and marked in Edit mode "Write this your way", until a form is chosen in Settings, when those words appear in it. A board's description (its note to the people around the person: what it is for, that nothing is sent, that it does not replace alarms or monitoring) is shown as a line above the board. Pictures: when a person exports boards for another app, the export already embeds each cell's symbol as a data: URI from the chosen set's sprite (Cell::symbol → symbols::symbol_for_cell → ObfExportOptions::sprites), so nothing more was needed there.

In the shared chooser. The sets are offered by the core page-set catalogue and chooser (tools/pagesets/catalog.py, aac_core::pagesets, aac-web pagesets.rs and catalogue_sets.rs), beside Growing Core and Fixed Paths, at setup ("Words to start with") and in Settings → Words and boards. There is no second chooser.

  1. The generator. build.py --out DIR writes, beside the packages, DIR/families.json in the catalogue's generator contract: four families (phrases-adult, phrases-intent, phrases-themes, phrases-emergent, chooser: "phrases"), one package per set, language and speaker form (99), each with lang, gender ("f" / "m" / null), size ("12", "20", "40" for intent first, else ""), rows, cols, home, label, description, boards, cells and cells_in_english; languages[code] is GlossOnly with the share agreed (a translation of English phrases is a gloss, SPEC §4.1, however good). tools/pagesets/generators.json lists it, and data/pagesets/index.json (the catalogue compiled into the app) lists all six families, 118 packages; catalog.py --check fails a build whose packages differ. The site's build puts the packages in /app/models/pagesets/.
  2. By language and speaker form. The chooser takes the package with Family::for_person(size, variant, locale, speaker_form): the person's language (exact tag, then base), in their form where that language's packages differ by it, else the English one. Where a set's words in the person's language change with who says them (Family:: speaker_form_matters) and AacProfile::speaker_form is not set, setup shows "Words about myself" with the set and will not start until it is answered; Settings asks it when Add is pressed and adds the set once it is answered. Never assumed; the answer is kept on the profile and can be changed in Settings → Language, which shows the question only for a language where some set's words differ (phrase_sets:: speaker_form_matters, from the catalogue).
  3. How far the language goes. Each family says what it is, its sources and licence, and, for a language other than English, its language_note and, for the chosen size, "All of it is in Spanish." or "1 of its 366 cells is still in English, and says so." from the package's cells_in_english; a language with no package of its own gets the note alone (in English for now).
  4. Adding. pagesets::add / start_with → prepare → obf::import_obz, give_new_ids, editing::add_boards_as_page_set; the import's warning is shown with the result (each package keeps, and names, page numbers for a printed book; all but Themed phrases, cells to fill in; First switches, animations). Each board keeps its licence (CC BY-SA), so re-sharing keeps the attribution.
  5. After adding. If the set has ext_aurasense_fill_in cells (adult: names, photos, scripts, own voice; emergent: own message, news, photo choices), open Edit mode's list of them: "Fill in your details". For the adult set, offer later "Make Simple page my home" (the staged plan in DESIGN-adult.md).
  6. Setup. The setup wizard can offer the matching set by the path the person picks: an adult whose talking has changed → Adult conversation; a first switch user → First switches and messages; someone starting out → Intent first (12); a reader who wants quick phrases → Themed phrases.
  7. Behaviours. Built (see above), except fill-in badges and effects, which are kept and named in the import's warning. In a client without them the sets still work: sequences say their first line, popups stay open (every page has Back or Start), speak-only boards also add to the message, links that carry words only open the page. Track A's per-person setting "After a word on another board, go back to Home" (AccessPrefs::return_home) wins over a popup's return to its opener; the person can also keep popups open (AccessPrefs::popups_close, Access settings → Going back).

Tests

crates/aac-core/tests/pagesets_phrases.rs runs build.py --out into Cargo's per-test temporary directory (it needs Python 3.11+ with PyYAML; AAC_PYTHON names the interpreter), then checks every package in the catalogue, English and every language and speaker form:

  • the catalogue lists all six sets in English and ten languages, its files match the directory, and its sizes are the files';
  • every package validates with the independent open_board_format crate (no errors), and imports with the app's own obf::import_obz with no warnings, every board present and the root first;
  • every cell sits inside its grid, one per place; every link lands on a board of the package; every board is reachable from the root;
  • every ext_aurasense_symbol is a concept of the app's symbol index; every picture names a symbol its set has, is in the package, and carries its CC BY-SA licence;
  • every language's package has the same boards with the same cell ids in the same places as the English one;
  • every cell of a language package is either wholly in that language (and says it was agreed by two readers) or marked as English, and a board with English left on it says so;
  • imported with the app's importer, a translated cell is the person's own words in that language (Cell::lang), an English cell is an English key, and every chosen symbol is kept (Cell::symbol);
  • sequences have two lines or more, valid order and ending, lines that name cells of the same board, and say their first line to a client without the extension; board behaviours are only the two defined;
  • in the intent-first sets, each operational command (Oops, I'm finished, Back to the start, Go back, Turn the page) is in one place on every page.

build.py --check adds: the sources are valid (every guard above), two builds are byte-identical, and reports/ is current.

Decisions for the founder

  1. Speaker gender. Decided: "Words about myself: feminine / masculine", shown only for es, fr, pt, it, hi, ru, asked when a set in one of them is added, no default, changeable in Settings. Built.
  2. Address. Adult set: polite address (usted, vous, Sie, Lei, Вы, です/ます); emergent set: familiar; intent and themes: familiar with family and helpers. An informal adult variant (to family) would double the adult set's translations; not proposed now.
  3. Pictures in language packages. Decided: language packages name symbols; the app embeds the pictures when a person exports boards for another app (it already does).
  4. The importer defect. Decided and fixed (above).
  5. The SPEC text. Approved as draft text after 0.2.0; in SPEC.md.
  6. Native review. Every translation is model-read only. Which languages get native reviewers first (the AAC site's largest audiences), and who.
  7. Name collision. Decided. TD Snap has an "Express" page set, and the app was previously called Express too; it is now the AAC Reference App. Our page set is called "Themed phrases", and nothing here uses the word.