<?xml version="1.0" encoding="UTF-8"?>
<spec xmlns="https://vibevm.org/spec/1">
  <title id="root">The structural loader — honouring directives without the static compiler</title>
  <status stage="spec" state="done" action="continue" actionstage="impl" comment="B0 2026-07-24: DESIGN provisional (PROP-035 S13); authored, not yet wired into any live boot"/>
  <p p="1"><fact id="status-line" status="spec/work">**Status:** DESIGN — provisional (PROP-035 §13). These instructions are authored but **not yet wired into any live boot**: migration is demo-corpus-first, `org.vibevm.world` next, vibevm's own boot last (PROP-035 §15). This document is the reference text; a package that adopts the spec-compiler format will load it (or its successor) first.</fact></p>
  <section id="what" title="What this is">
    <p p="2"><fact id="LOADER-DEFINITION" status="spec/done">The **first-loaded instructions** that make an agent honour the spec-compiler directives (`#use` / `#embed` / `#source` / `@spec`) in **structural mode** — reading on demand — the lazy counterpart to the algorithmic static compiler (PROP-035 §2). Until a hard algorithmic agent exists (§14), an LLM executes them.</fact></p>
    <p p="3"><fact id="MUST-LOAD-FIRST" status="spec/done">A project or package that manages its content this way MUST load these instructions before anything else; without them the directives are inert prose. A managed project or package that omits them is **broken** (§13), and the project/package-creation tools must inject them.</fact></p>
    <p p="4"><fact id="SAME-EFFECTIVE-SPEC" status="spec/done">The one hard contract: your structural reading MUST reach the **same effective spec** the static compiler would produce. The static compiler is the reference semantics; you are its lazy executor (§2).</fact></p>
  </section>
  <section id="use" title="`#use spec://…` and `@spec://…` — dependency edges">
    <p p="5"><fact id="use-lead" status="spec/done">When you meet `#use spec://X` — or the in-place `@spec://X` — treat X as a dependency:</fact></p>
    <list ordered="false" p="6">
      <item><fact id="USE-READ-BEFORE-USE" status="spec/done">**Read X before using anything defined in it.** Not eagerly on sight, but **before first use** of any entity X names.</fact></item>
      <item><fact id="USE-CASCADE" status="spec/done">**Reads cascade.** If X itself `#use`s Y, read Y too, and so on. This is how a large package is entered through one file and expands only along what is actually used (tree-shaking) rather than loaded whole.</fact></item>
      <item><fact id="USE-AT-MANDATORY" status="spec/done">**`@spec://` (with the `@`) is mandatory** — always read it on first encounter. A **bare `spec://`** (no `@`) is discretionary: read it only if you need what it names.</fact></item>
    </list>
  </section>
  <section id="embed" title="`#embed spec://…` — the macro splice">
    <p p="7"><fact id="EMBED-MACRO" status="spec/done">`#embed` is a materialization-time macro (§7.1). In a properly installed package it is **already expanded** — you will normally see the spliced text, not the directive. If you do meet an unexpanded `#embed spec://X`, read X's section and treat its text as spliced in place.</fact></p>
  </section>
  <section id="source" title="`#source spec://…` — contract → implementation">
    <p p="8"><fact id="SOURCE-CONTRACT-IMPL" status="spec/done">A short `contract` section names its heavy implementation via `#source spec://X`. When you need the **full behaviour** behind a contract section (not just its summary), read the `#source` target and combine it with the contract text by the marker on the **source** heading:</fact></p>
    <list ordered="false" p="9">
      <item><fact id="SOURCE-REPLACE" status="spec/done">`:replace` — the source text is canonical; ignore the contract text.</fact></item>
      <item><fact id="SOURCE-ADD-DEFAULT" status="spec/done">`:add` (the default) — use **both**, contract first then source.</fact></item>
    </list>
    <p p="10"><fact id="SOURCE-OPTIONAL" status="spec/done">A contract section with no `#source`, or whose behaviour you do not need, is read as-is.</fact></p>
  </section>
  <section id="read-set" title="The read-set — read once, survive compaction">
    <p p="11"><fact id="READ-SET-FILE" status="spec/done">To avoid re-reading the same target endlessly, keep a persistent **read-set** at `.vibe/session/read-set.json`. Before reading an `@spec` target, consult it; after reading, append `{ specpath, content_hash }`. Reuse specmap's `content_hash`, so a **changed** target is re-read.</fact></p>
    <p p="12"><fact id="READ-SET-SURVIVES-COMPACTION" status="spec/done">This survives context compaction because **these instructions are re-read at boot**, so the habit of consulting the read-set is restored even after the conversation is summarized.</fact></p>
    <p p="13"><fact id="READ-SET-SEMANTICS" status="spec/done">Crucially, the read-set records **what exists and where, not what is currently in your context**. Compaction evicts the *text* but not the *fact*. So the rule is: read an `@spec` target if **(a)** it is not in the read-set, **or (b)** it is in the read-set but its content is no longer in your context. Re-reading is cheap — the file sits in `vibedeps/`. Think of the read-set as a linker symbol table, but for what you have read.</fact></p>
  </section>
  <section id="never" title="Never">
    <list ordered="false" p="14">
      <item><fact id="NEVER-USE-UNREAD" status="spec/done">Never use an entity from a `#use` / `@spec` target without reading the target first.</fact></item>
      <item><fact id="NEVER-DOUBLE-READ" status="spec/done">Never re-read an `@spec` target that is both already in the read-set **and** still in your context.</fact></item>
      <item><fact id="NEVER-BARE-MANDATORY" status="spec/done">Never treat a bare `spec://` as mandatory — only `@spec://` compels a read.</fact></item>
      <item><fact id="NEVER-DIVERGE" status="spec/done">Never let structural reading diverge from what the static compiler would produce (§2).</fact></item>
    </list>
  </section>
</spec>
