description: How .me tracks reactive dependencies from leaves back to derived semantic paths.
An Introduction to .me - Inverted Dependency Indexing
.me is a semantic kernel built around paths.
You can write:
me.order.price(100);
me.order.quantity(5);
me.order["="]("total", "price * quantity");
And read:
me("order.total"); // 500
At the surface, this looks like a free-form object.
Underneath, it is a reactive dependency graph.
The important part is how .me updates derived values without scanning the entire tree.
That mechanism is Inverted Dependency Indexing.
The Problem
In a normal tree, data flows from root to leaf:
order
price
quantity
total
A naive reactive system might handle a mutation by asking:
What changed?
What depends on it?
Do I need to scan the tree?
Do I need to recompute all formulas?
That becomes expensive as the graph grows.
If the system has N paths, a global scan makes the cost of one local update depend on total graph size.
.me avoids that by indexing dependencies in the opposite direction.
The Inversion
When a derived value is declared:
me.order["="]("total", "price * quantity");
.me records:
order.total depends on:
order.price
order.quantity
But it also builds the reverse mapping:
order.price -> order.total
order.quantity -> order.total
That reverse mapping is the inverted dependency index.
In the TypeScript kernel, this is represented by refSubscribers:
refSubscribers: Record<string, Set<string>>
Conceptually:
refSubscribers["order.price"].add("order.total");
refSubscribers["order.quantity"].add("order.total");
Now a write does not need to search the graph.
When this happens:
me.order.price(200);
the kernel can directly ask:
Who subscribes to order.price?
And the answer is already indexed:
order.total
Registration Time
The work starts when a derivation is registered.
.me extracts references from the expression:
"price * quantity"
Then resolves them relative to the current path:
price -> order.price
quantity -> order.quantity
Then stores the derivation target:
order.total
The derivation record contains:
expression
evaluation scope
resolved refs
last computed time
The inverted index contains:
ref path -> dependent target paths
This is the key shift.
The kernel does not wait until mutation time to discover the dependency structure. It builds the structure when the derivation is declared.
Mutation Time
When a value changes:
me.order.price(200);
the kernel calls its invalidation path.
In eager mode, the algorithm is:
1. start from changed path
2. look up subscribers in refSubscribers
3. recompute those targets
4. push recomputed targets back into the queue
5. continue until the affected frontier is done
So if another derivation depends on order.total, it can continue bubbling upward:
me.order["="]("total", "price * quantity");
me.order["="]("withTax", "total * 1.16");
A price mutation affects:
order.price
-> order.total
-> order.withTax
The kernel follows that chain directly.
It does not scan unrelated paths.
O(k), Not O(N)
The practical complexity is based on k, the affected dependency frontier.
N = total graph size
k = number of derived nodes affected by this mutation
If the graph has one million paths but only three derived nodes depend on the changed value, the mutation should touch those three derived nodes, not the full million.
That is the point of Inverted Dependency Indexing:
cost(update) ~= O(k)
Not:
cost(update) ~= O(N)
This is not magic. If one path has 100,000 subscribers, then k = 100,000, and the update is expensive. The optimization works when dependencies are local and the affected frontier stays small.
Eager vs Lazy
.me supports two recomputation modes.
In eager mode, mutation immediately recomputes affected subscribers.
write source
-> find subscribers
-> recompute now
In lazy mode, mutation only bumps reference versions.
write source
-> mark dependency version changed
-> recompute later on read
The runtime control lives under the reflective plane:
me["!"].runtime.setRecomputeMode("lazy");
Then, when a derived value is read:
me("order.total");
the kernel checks whether its dependency versions are stale. If they are stale, it recomputes the target before returning the value.
So eager mode pushes work into writes.
Lazy mode pulls work into reads.
Explainability
Because recomputation is tracked as a wave, .me can explain what happened.
me["!"].explain("order.total");
A derived path can report:
expression
dependency inputs
last recompute wave
k
source path
For example:
order.total
expression: price * quantity
depends on:
order.price
order.quantity
This matters because a reactive system should not be a black box. If a value changed, the kernel should be able to show the path of causality.
Secret Scopes
The same model can operate across secret branches.
.me supports path-bound secret scopes:
me.wallet["_"]("wallet-key");
me.wallet.balance(12480);
The root remains stealth:
me("wallet"); // undefined
But internal derived logic can still use the encrypted branch under the kernel’s rules.
When explain() crosses a secret input, it masks the value instead of exposing it:
origin: "stealth"
value: "●●●●"
So dependency tracking and structural silence can coexist.
The dependency graph still works, but public inspection does not leak private values.
The Mental Model
In a regular index:
path -> value
In an inverted dependency index:
source path -> derived targets
So .me keeps both ideas:
semantic path -> current value
dependency ref path -> subscribers
The first lets the kernel read meaning.
The second lets the kernel update meaning efficiently.
Why It Matters
.me starts with free-form paths:
me.whatever.you.want("x");
But once paths can derive from other paths, the runtime needs a way to preserve consistency.
Inverted Dependency Indexing is that mechanism.
It lets .me behave like a living semantic graph without treating every mutation as a whole-graph event.
The design is simple:
declare meaning freely
record dependencies when formulas are created
invert those dependencies into subscribers
update only the affected frontier
explain the recompute path when needed
That is the core of .me reactivity:
free-form semantics on the outside
indexed dependency causality underneath
Top comments (0)