# `PtcRunner.Lisp.Analyze.PreludeScope`
[🔗](https://github.com/andreasronge/ptc_runner/blob/main/lib/ptc_runner/lisp/analyze/prelude_scope.ex#L1)

Process-local scope for the compiled prelude consulted during a single
analysis pass (Capability Prelude V1, plan §4 / §2).

The analyzer's `do_analyze/2` is deeply mutually-recursive across ~80
clauses; threading the prelude artifact through every clause would be a
cascading refactor for a value only the qualified-`ns_symbol` clauses and the
qualified-definition (protected-write) clauses need. Instead the prelude is
stashed in the process dictionary for the duration of one `analyze/2` call
(set on entry, restored on exit via `with_prelude/2`). Analysis runs in a
fresh bounded sandbox process per `PtcRunner.Lisp.run`, so this state is
naturally request-scoped and never shared across runs.

Two questions this module answers for qualified names like `crm/get-user`,
where `ns`/`symbol` arrive STRING-backed (unknown namespaces are not in
`SourceAtoms` so they intern as `{:ns_symbol, "crm", "get-user"}` — fact #1):

  * `fetch_export/2` — is `ns/symbol` a PUBLIC prelude export, and what is its
    arity? Private helpers (`defn-`) have no export record, so they are
    absent here and stay unreachable by qualified user calls (plan §5 / §8).
  * `protected_namespace?/1` — is `ns` a protected namespace (a reserved host
    namespace or one declared by the attached prelude)? Used to reject
    `(def ns/x ...)` / `(defn ns/f ...)` writes with a protection fault rather
    than a generic invalid-qualified-name syntax error (plan §2).

# `current`

```elixir
@spec current() :: PtcRunner.Lisp.Prelude.t() | nil
```

The prelude installed for the current analysis pass, or `nil`.

# `fetch_export`

```elixir
@spec fetch_export(term(), term()) ::
  {:ok, PtcRunner.Lisp.Prelude.Export.t()} | :error
```

Looks up `ns/symbol` (both STRING-backed) in the current prelude's PUBLIC
export table. Returns `{:ok, %Export{}}` or `:error`.

# `prelude_namespace?`

```elixir
@spec prelude_namespace?(term()) :: boolean()
```

Whether `ns` is a namespace DECLARED by the attached prelude (not the
reserved host namespaces). Used to turn a qualified call into a known
namespace's unknown export into an actionable discovery hint.

# `protected_namespace?`

```elixir
@spec protected_namespace?(term()) :: boolean()
```

Whether `ns` is a protected namespace for the current analysis pass: a
reserved host namespace, or one declared by the attached prelude. Used to
reject writes (`def`/`defn`) into protected namespaces (plan §2).

# `with_prelude`

```elixir
@spec with_prelude(PtcRunner.Lisp.Prelude.t() | nil, (-&gt; result)) :: result
when result: term()
```

Runs `fun` with `prelude` installed as the analysis-pass prelude scope,
restoring any previously installed scope afterward.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
