Affinity Model

Affinity is emergent — store reactions, derive affinity as executable graph logic.

Affinity Model cover: a face dissolving into clouds

The idea

No ratings table, no affinity column. People react; affinity is what the graph derives from it.

01

Reactions are facts

Store what people did. Each tap is one write into the semantic tree.

me.contexts[123].targets[1].hearts(2)
02

Affinity is derived

A formula, not a stored number. When a reaction changes, only the nodes that depend on it recompute (k).

targets["[i]"]["="]("affinity_score",
  "score_sum / reactions")
03

explain() shows why

Ask any derived value for its receipt: the expression and every input value it used.

me.explain("contexts[123].targets[1].affinity_score")

Live: the real kernel in your browser

Tap a reaction. Every number is read from the kernel, and the explain() panel is the kernel's own output.

Loading this.me@4.1.0 and checking its sha256…

Facts → derived contexts[123]

weights (facts):

Writes k = nodes recomputed (explain().meta.k)

No writes yet. Tap + or − on a reaction.
recomputed: —
me.explain("…affinity_score")
waiting for the kernel…

What runs here: the unmodified this.me@4.1.0 (jsDelivr, unpkg fallback), sha256-checked before import. 4.1.0 formulas are arithmetic and comparisons over paths: no string literals, ternaries, map/filter/reduce, sum or count. So the walkthrough's emoji ternary becomes weight facts, reactions are per-target tallies, sums are explicit, and indices use brackets (targets[1]; targets.1 silently reads undefined). With zero reactions, score_sum / reactions divides by zero and the kernel returns undefined. Page code only draws, sends the writes, and runs the fresh-rebuild comparison.

Every call this demo made to seed the kernel
—