Proxy Calls
How me.whatever(what) works in the TypeScript kernel, this.me 4.2.1: one callable object, a JavaScript Proxy, turns property access into a path and a call into a write or a read.
Concept first: me.whatever(what) (writing and reading paths) · me.explain(path) (why a value has its value). This page maps that onto the source.
Source map
All links are pinned to tag v4.2.1 (the commit published to npm as this.me 4.2.1).
| File | Role | Where |
|---|---|---|
proxy.ts | Builds the path from property access; decides member vs path | createProxy L256–303 · member check L287–292 · normalizeArgs L32–36 |
handleCall.ts | Routes a call: root read, seed, root postulate, path write | handleCall L87–156 |
core-write.ts | Every write | postulate L983–1101 · declareDerivation L1129–1137 |
core.ts | Reads | readPath L289–393 |
operators.ts | Detects operator calls such as ["="] | isEvalCall L196–223 |
derivation.ts | Formulas, dependencies, invalidation, explain | explain L140–251 · registerDerivation L577–608 · invalidateFromPaths L824–961 |
me.ts | The ME class and its members | class ME L254 · inspect / explain L474–484 · readPath L1548–1554 |
The example
Run against this.me 4.2.1 (npm):
import ME from "this.me";
const me = new ME();
me.colony.pantry.seeds(40);
me.colony.pantry.honey(12);
me.colony["="]("food", "pantry.seeds + pantry.honey");
me("colony.food"); // → 52
me.colony.pantry.seeds(45);
me("colony.food"); // → 57
me.explain("colony.food"); // → below{
"path": "colony.food",
"value": 57,
"expr": "pantry.seeds + pantry.honey",
"derivation": {
"expression": "pantry.seeds + pantry.honey",
"inputs": [
{ "label": "pantry.seeds", "path": "colony.pantry.seeds", "value": 45, "origin": "public", "masked": false, "status": "resolved" },
{ "label": "pantry.honey", "path": "colony.pantry.honey", "value": 12, "origin": "public", "masked": false, "status": "resolved" }
]
},
"meta": {
"dependsOn": ["colony.pantry.seeds", "colony.pantry.honey"],
"k": 1,
"recomputed": ["colony.food"],
"changed": ["colony.food"],
"sourcePath": "colony.pantry.seeds"
}
}(lastComputedAt / recomputedAt timestamps omitted.)
1. Property access builds a path
me is a function wrapped in a Proxy (L256–303). Its get trap (L283–298) checks, in order:
- a symbol → returned from the target;
"!"→ the runtime plane,createRuntimeProxy(L216);prop in self→ a member of the kernel instance: methods are returned bound to the caller scope (L287–292);- anything else → a new proxy one segment deeper:
[...path, prop](L296–297).
So me.colony.pantry.seeds is a proxy holding ["colony", "pantry", "seeds"]; nothing is read or written yet.
The member check runs at every depth, not only on the root: every proxy shares the same self. me.colony.explain is the explain method, not the path colony.explain:
typeof me.colony.explain; // → "function"
me.colony.explain("colony.food").value; // → 57Members are the ME instance API (me.ts L474–919): explain, inspect, execute, exportSnapshot, hydrate, learn, setRecomputeMode, … plus inherited names such as toString. Any other name is a path.
2. A call is routed by handleCall
Calling a proxy runs its function body (L261–280) → handleCall:
| Call | Route | Lines |
|---|---|---|
me("a.b"), me("a"), me("_x") | read: readPath | L89–111 |
me("ana", "luna") | seed identity (who + secret) | L113–125 |
me() | root proxy | L128–130 |
me(expression) | root postulate | L133–137 |
me.a.b(v) | write at a.b, returns a proxy for chaining | L141–155 |
Arguments go through normalizeArgs: none → undefined, one → the value, several → an array. That is why me.a.b() is a write of undefined, not a read.
3. Write: me.colony.pantry.seeds(45)
handleCall(non-root) →self.postulate(path, 45)(me.ts L1342).postulate: operator checks; a plain value is normalized and committed —commitValueMapping→commitMemoryOnly(hash-chained memory) →applyMemoryToIndex.invalidateFromPathsrecomputes dependents: herecolony.food(k = 1,sourcePath = "colony.pantry.seeds"above).handleCallreturns a proxy on the same branch (L147–155).
4. Read: me("colony.food")
- Root call with one string:
classifyPathExpression(aggregate strings go toreadPathExpression); a dotted path goes toreadPath(L97–110). ME.readPath: stealth check for the caller scope (L1520).Core.readPath: transforms → selections → lazy refresh (ensureTargetFresh) → filters → secret branch scope → index / pointers.
5. Formula: me.colony["="]("food", "pantry.seeds + pantry.honey")
"="is not a member, so the path is["colony", "="]; the call passes["food", "pantry.seeds + pantry.honey"].isEvalCallrecognises the operator insidepostulate.declareDerivation:registerDerivation(inputscolony.pantry.seeds,colony.pantry.honey) →computeDerivation→postulate(colony.food, 52, "=").- The chain continues on
colony, the scope, because the leaf was an operator (L148–149).
6. me.explain("colony.food")
explain is a member (step 1) → ME.explain → Derivation.explain: the value, expr, derivation.inputs (masked when an input is under a secret the caller can't see) and meta from the last recompute wave.
Rust
Rust has no Proxy. Members are methods on Kernel and a path is always an argument, so a path can never shadow a member: kernel.postulate("a.b", v), kernel.read("a.b"), kernel.explain("a.b"). Strings become paths through IntoPath (rust-v0.3.3); postulate is at mod.rs L633–639. See the Rust API.
Tests
dsl.contract.test.mjs at v4.2.1:
- boot + basic set/get
- callable proxy survives hydrate
- runtime escape plane
me["!"] - explain() masks stealth inputs
- explain() exposes expr and recompute wave metadata
See also
Runtime Surface · Operators · Syntax · API: ME class · me.whatever(what) · me.explain(path)