Skip to Content
Living documentation — last reviewed 2026-05-28
FeaturesExercisesMovement lookup and alias review

Movement lookup and alias review

Movement lookup checks exact names and aliases before fuzzy suggestions. Organization membership and exercise ownership determine which rows are visible.

Canonical and organization ownership

The shared library contains canonical exercises with organizationId: null, maintained through platform-admin tools. Coaches create organization-owned exercises for local movements. Custom rows and forks belong only to their organization and never become canonical automatically.

Editing a canonical exercise creates an organization-owned copy with a new ID and forkedFromId pointing to the source. Repeated edits reuse that organization’s live fork. The copy includes the effective fields at creation, including previous local overrides, and later canonical changes do not overwrite it. The API returns the fork ID; clients use it for subsequent edits and new workout selections. Existing draft workout definitions and unpublished programming in that organization adopt the fork. If a source also serves published or logged work, the draft gets a separate mutable workout copy and a fresh unpublished release; the published source, issued releases, results, and other organizations stay unchanged.

Legacy exercise_org_overrides remain available to existing references; they never mutate the shared row. Resetting an override affects only that legacy override. Forks use the existing custom-exercise editing and soft-delete flows.

Search and resolution prefer the calling organization’s fork of a matching canonical exercise for all selections. Other organizations’ custom rows and forks are excluded. The library browser can still list the canonical source and the private copy separately. Unrelated exact matches remain ambiguous; a shared name alone never establishes fork lineage. Canonical collision reports inspect only shared rows, excluding custom exercises and organization overrides.

Search and resolve

GET /exercises/search, read.exercises_search, and read.exercises_resolve_batch put normalized exact names and aliases before fuzzy results. Normalization folds case, removes spaces, apostrophes, hyphens and en/em dashes, and drops the plural ending of established movement words (squats, lunges, pulls, openers, dislocations, switches, …; see MOVEMENT_PLURAL in exercise-identity.ts), so “banded face pulls” matches the alias “banded face pull”. Words outside that list keep their ending, so press never becomes pres. A canonical name remains searchable when the organization gives that exercise a local name. Canonical aliases and local aliases are both searchable, but local aliases apply only to that organization.

The response carries matchKind. Confidence is a fixed band: exact_name is 1, exact_alias is 0.95, and fuzzy is 0.5. The fuzzy band indicates a suggestion for review, never an automatic identity match. Resolve checks every exact row before applying the display limit. If several rows share an exact alias or name, it returns all candidates with bestId: null and ambiguous: true. If exact lookup fails, resolve returns unresolved.

MCP offers exercises_add_alias to add a local alias to a canonical row, exercises_create_custom to create or reuse an organization exercise by name (optionally with mediaUrl), and exercises_set_media to set or clear the organization’s demo media for an exercise. All require owner, admin, or coach access. The alias tool adds the alias to the organization-owned fork. It never edits canonical aliases.

Canonical collision review

Platform admins can call GET /admin/exercises/canonical/alias-collisions for a read-only report of every normalized term shared by live canonical rows. Terms are normalized exactly as the exact lookup normalizes them (case, spaces, apostrophes, dashes and movement plurals), so the report lists every term that makes resolve ambiguous. Each entry includes the rows and a proposed owner only when exactly one row’s canonical name equals the term. Otherwise proposedOwnerId is null and a person must decide. The admin app’s “Alias collisions” card resolves a term with a dry run before writing.

The platform-admin guard is required for every canonical maintenance endpoint. Organization coaches cannot edit shared canonical entries.

For POST /admin/exercises/canonical/duplicates, merge candidates require the same movement pattern and embedding cosine at least 0.92. Shared aliases appear in aliasCollisions and do not create merge candidates. Collision review is invoked on demand by a platform admin.

After review, a platform admin can call POST /admin/exercises/canonical/alias-change with sourceId, alias, and an optional targetId. Omit targetId to remove the alias from the source. Pass dryRun: true to inspect the plan. A write records the source and target alias arrays before and after in audit_logs.metadata; those arrays are the rollback record for a reviewed correction. The service serializes edits to the same normalized term, refreshes canonical embeddings using name, aliases, and cues, and returns reEmbedded so the operator can see when refresh was unavailable. Production corrections require separate owner review and are not performed by the report.