The bounded type oracle: what a node's type is, and where its name came from.
This is the "bounded oracle" of the type-aware rules design, and the bound is depth
rather than the file. [TypeScriptOracle] answers from one parse and nothing else;
[BuiltinProvider] wraps it and follows an import out of that file — to a sibling source,
to a .d.ts, into node_modules — through the caller's [lanekeep_core::FileAccess], so
every file it opens is a recorded dependency of the answer. What it still has no notion of
is a program: no tsconfig.json, no path mapping, no compiler, and a fixed number of
hops rather than a transitive closure.
It answers None whenever it cannot be sure. That is the whole contract: a rule choosing
to be silent on None is sound, and one choosing to report on it is the author's decision
rather than the engine's.
Why this is its own crate
It reaches declarations through [lanekeep_lang::binding::BindingResolver::declaration_of]
and [lanekeep_lang::binding::BindingResolver::declares], two language-neutral questions,
so it never needs a language crate's internals — lanekeep-lang-js is a dependency of its
tests alone. Only its knowledge of TypeScript syntax is language-specific, and that is
held in one type whose constructor refuses a grammar that does not speak it.
What is deliberately absent
No clock, no environment, no randomness, no HashMap iteration, and no filesystem access
that is not a [lanekeep_core::FileAccess] read. A cached result computed by this oracle
must still be valid, so nothing here may observe anything the cache key does not cover: the
bytes it was handed, and the tracked reads it made from them.