Remote / foldkit-remote
Introspection
Remote exposes its decisions as data rather than requiring DevTools to reach into private state:
Data.inspect(model) // serializable cache/domain summary
Data.plan(model, projection) // the entity plan a read would execute
Data.meta(model, projection) // when what is shown was received, stale/loading
Data.explain(model, query) // what one query read is, and currently is
Remote.planQueries(...) // missing/stale query work
Remote.inspectEntity(...) // one normalized entityData.meta is for views, not debugging: updatedAt is the newest server
write among what the projection shows (undefined when nothing shown was
received), with stale and loading beside it, so "updated 5s ago" reads
the Model like any other render.
These are pure and useful in tests, tooling, and debugging. For a read that
stays Initial, Data.why and Data.plan are the tools; see
Why is it still Initial?.
Data.inspect(model).loading answers the other one — "what is Remote doing
right now?" — with the entity\0id\0field marks of the reads in flight,
beside mutations.pending for the writes. Both are read from the Model, not
from the fibers doing the work: a tool that shows them shows something a
recorded Model can be replayed to, and nothing that needs the runtime to be
asked. That is deliberate. Runtime activity is not a second source of truth
here, and a view that rendered from it would stop being reproducible from the
Model.
Explaining one query read
A query read is assembled from more pieces than it looks like: a definition, an
input, a connection identity that excludes the window, a window that does not,
and a Selection that is a slice asked of the server. Data.explain puts them in
one serializable value, beside what the read answers from this Model right now:
Data.explain(model, projects)
// {
// domain: 'remote',
// query: 'ProjectsByOwner',
// input: { ownerId: 'u1' },
// identity: 'ProjectsByOwner\u0000{"ownerId":"u1"}',
// window: { first: 25 },
// select: { entity: 'Project', fields: ['id', 'name'] },
// body: 'FROM Project\nWHERE Project.ownerId = $ownerId\nORDER BY Project.name DESC',
// dependencies: { fields: [...], inputs: ['ownerId'], operations: ['eq'] },
// state: 'Ready',
// }body is the query's meaning as readable text, and it is neither SQL nor
whatever the backend compiled — an input shows as $ownerId rather than a bound
parameter, and contains is named rather than rendered as somebody's like. A
definition made with Query.make has no body, because its meaning lives on
the server that answers it.
state comes from the projection's own read, so an explanation and the view
cannot disagree about whether the data is there.
A Projection cannot say which Surfaces read it — several may — so pass the
active record subscriptions takes and explain reports all of them, plus why
each is active where that is a readable fact (Surface.when) rather than a
callback (Surface.at):
Data.explain(model, projects, { surfaces: actives })
// surfaces: ['ProjectPage']
// activation: [{ surface: 'ProjectPage', path: ['route'], tag: 'Project' }]A Surface.each family reports each reading instance as Child[key].
There is still no executor, because what answers a query is a
RemoteClient Layer in the runtime rather than a value in the Model — the same
purity that lets this be replayed from a recorded Model is what keeps it out of
reach.