Read-only introspection over the callable PTC-Lisp surface.
Backs the dir, apropos, doc, export-meta, and source builtins.
dir, export-meta, and source describe the attached prelude. apropos
and doc additionally expose fixed built-ins and the bounded Java surface
from PtcRunner.Lisp.Registry. The same answers are produced in the REPL, in
workflow and mission source, and inside a prelude export reading another
prelude's documentation — there is no REPL-only path.
Ref arguments accept a string or a {:symbol_ref, name} runtime value (from
a quoted symbol, or from the analyzer's bare-symbol rewrite on these forms).
meta is intentionally not included: in Clojure it is an ordinary function
over values, not a discovery form. source resolves only against the
attached prelude's compile-time source_index — there is no registry
fallthrough.
Attached prelude visibility
Only public export records (%PtcRunner.Lisp.Prelude.Export{}), which cover
both :prompt and :discoverable visibility. Private defn- helpers have no
export record and are unreachable by qualified call, so they are absent from
dir/apropos/doc/export-meta. source is the exception: it can reveal
a private helper that is transitively reachable from a visible public
export, via Prelude.source_index (not form_graph callables).
Namespaces are derived from the visible export set rather than from
Prelude.namespaces/1, so a namespace holding only private helpers does not
appear in namespaces/2.
Visibility filter
Callers pass a predicate over export records rather than any runtime context,
keeping this module pure. PtcRunner.Lisp.Eval.Apply builds it from the
evaluation context so that what a program can discover matches what it can
call: PtcRunner.Lisp.Eval.Context.prelude_ref_visible?/2 supplies the
strict_transitive_calls half, and the run's prelude_export_mask supplies
the discovery half. A narrowed session grant needs no filter here — it hands
the run a prelude whose exports list is already the narrow set.
How the reported effect is bounded
Export.effect joins an export's own declaration with those of the prelude
helpers it calls, but not with the effects of the capabilities it reaches.
The authoritative value is the mission-resolved effect
PtcRunner.Kernel.MissionInventory publishes, which adds that last join: a
wrapper declaring :read over a capability installed as :write resolves to
:write. Producing it needs the mission's capability set, which this layer
does not have.
Reporting the raw declaration would therefore let a program read :read for
an operation the inventory calls :write — the direction that invites
repeating an irreversible call. Omitting the effect is no better: the
inventory covers only Prelude.prompt_exports/1, so a :discoverable export
is callable with no effect stated anywhere.
So the reported effect is deliberately weakened rather than dropped. An export
that reaches no capability is reported as declared. An export that does reach
one is reported as :write if anything in its chain declares :write, and
:unknown otherwise. It can still fall short of a :write the inventory
resolves, but it never calls something :read that touches a capability, so
no answer here presents an unresolved effect as safe.
Misses
An exact attached export occupies its ref before its visibility filter is
applied. A hidden attached ref therefore cannot fall through to registry
documentation for the same spelling. Otherwise doc falls back to the
registry, and apropos merges visible attached refs with canonical registry
names. An unknown or malformed ref is a miss, not a failure.
Summary
Functions
Sorted visible export refs and canonical registry names matching query.
Sorted visible export refs declared by namespace.
Structured metadata for one visible export, or nil on a miss.
Validates arguments and answers one introspection call.
Sorted namespace names holding at least one visible export.
The introspection operations bound as {:special, op} builtins.
Rendered human-readable documentation for one visible attached export or fixed registry entry.
Rendered defining form for one attached prelude ref, or a miss notice.
Types
@type operation() :: :dir | :apropos | :doc | :export_meta | :source
@type visible() :: (PtcRunner.Lisp.Prelude.Export.t() -> boolean())
Functions
@spec apropos(PtcRunner.Lisp.Prelude.t() | nil, String.t(), visible()) :: [String.t()]
Sorted visible export refs and canonical registry names matching query.
Matching is a case-insensitive literal substring. Attached exports search their ref and docstring; registry entries search their name, signatures, description, notes, divergences, and section. A blank query matches nothing rather than everything — an empty search is not a request for the whole surface.
@spec dir(PtcRunner.Lisp.Prelude.t() | nil, String.t(), visible()) :: [String.t()]
Sorted visible export refs declared by namespace.
@spec export_meta(PtcRunner.Lisp.Prelude.t() | nil, String.t(), visible()) :: map() | nil
Structured metadata for one visible export, or nil on a miss.
Reports the calling contract: identity, arity, parameter names, call form,
docstring, visibility, effect, and any declared signature or type. The effect
is bounded as described in the module documentation. Capability wiring
(tool_refs, requires) and compiler internals (min_arity,
parsed_signature, parsed_type) stay out.
@spec invoke(operation(), [term()], PtcRunner.Lisp.Eval.Context.t()) :: {:ok, term()} | {:print, String.t()} | {:error, term()}
Validates arguments and answers one introspection call.
Every call path — direct application and higher-order dispatch — routes
through here, so argument faults and answers cannot differ between them.
doc answers {:print, text} because its text belongs on the print channel
rather than in the result.
@spec namespaces(PtcRunner.Lisp.Prelude.t() | nil, visible()) :: [String.t()]
Sorted namespace names holding at least one visible export.
@spec operations() :: [operation()]
The introspection operations bound as {:special, op} builtins.
@spec render_doc(PtcRunner.Lisp.Prelude.t() | nil, String.t(), visible()) :: String.t()
Rendered human-readable documentation for one visible attached export or fixed registry entry.
Callers print this rather than returning it, so documentation text is charged to the print budget instead of the result channel. An attached ref occupies its exact spelling before visibility is applied and therefore cannot fall through to registry documentation when hidden.
@spec render_source(PtcRunner.Lisp.Prelude.t() | nil, String.t(), visible()) :: String.t()
Rendered defining form for one attached prelude ref, or a miss notice.
Resolves only against Prelude.source_index — public exports and private
helpers transitively reachable from a visible public export. There is no
registry or filesystem fallthrough. Visibility matches the other discovery
forms: a masked or unauthorized public ref is a miss, and a private helper
is visible only when at least one public export that reaches it is visible.
Callers print this rather than returning it.