0070. A has-many names the inverse it follows with via=

0070. A has-many names the inverse it follows with via=

Status

Accepted

Date

2026-10-10

Deciders

operator (Saulo Vallory), accepting roadmap revision 5 on 2026-10-10 at 09:05, decision D7 with its recommended option.

Context

A has-many :memberships entity=Membership follows the key that Membership holds back to this entity. Hyper’s Membership has three belongs-to to Collaborator (collaborator, grantedBy, revokedBy) and its Dependency two to Task; the compiler accepts the has-many without saying which key it follows, and the model records no key (gap G28). The entities page reserves &name for a member of this entity, so via=&collaborator would name a member of the other entity with a spelling that means something else everywhere (ADR-0067).

Decision

has-many takes an optional via=, an atom naming the other entity’s belongs-to:

has-many :memberships entity=Membership via=:collaborator
  • With exactly one belongs-to from the other entity back to this one, via may be left out and that key is followed.
  • With more than one, via is required; omitting it is a build error that lists the candidates.
  • A via that names no belongs-to of the other entity, or one that points at a different entity, is a build error at the attribute, with a did-you-mean.
  • has-one is unchanged.

Options considered

  1. via=:collaborator, an atom (chosen). An atom names a declaration or a fixed-set value (ADR-0066); here it names a declaration in another entity.
  2. via=&collaborator. Reads as a member of this entity, which it is not.
  3. Infer from the name (:memberships follows membershipsId): breaks as soon as names differ from the keys.

Trade-off analysis

An atom is the only spelling in the file that names something without referring to this entity’s members. The build cannot check an atom against this entity’s members, so the check is a cross-file one (the other entity’s relationships), which the build already makes for entity=. The cost is one more option on has-many.

Consequences

  • The model records the key a has-many follows, which relationship loading (M7) needs.
  • Entities documents the option.

Action items

  • M7: the contract attribute, the cross-file check and the loader.