<?xml version="1.0" encoding="UTF-8"?>
<spec xmlns="https://vibevm.org/spec/1">
  <title>Design rationale: Loading &amp; boot composition model</title>
  <status stage="doc" state="done" comment="B0 2026-07-24: non-normative design record, captured 2026-05-21 in an owner session"/>
  <p p="1"><fact id="companion-line" status="doc/done">**Companion to:** [PROP-009](../modules/vibe-workspace/PROP-009-loading-model.xml) (the loading model — **shipped**, M1.18 phases 1–7, 2026-05-22).</fact></p>
  <p p="2"><fact id="rename-note" status="doc/done">**Terminology (2026-07-16 rename — read this before the body).** This record captures the 2026-05-21 session and keeps that session's three names; the shipped grammar has two. Read `inline` as **`link = "static"`** (the verbatim `STATIC.md` lane), the design's `static` as **`link = "dynamic"`** (the default, a by-reference `INDEX.md` read), and the design's `dynamic` as a **`dynamic` entry carrying a `when`**. The default moved with the names: design-`static` was the default and its shipped counterpart `dynamic` is. See [PROP-009 §2.4](../modules/vibe-workspace/PROP-009-loading-model.xml#inclusion-types), which is normative.</fact></p>
  <p p="3"><fact id="status-line" status="doc/done">**Status:** non-normative design record. Captured 2026-05-21 in an owner design session.</fact></p>
  <p p="4"><fact id="authority-line" status="doc/done">**Authority:** the PROP is the contract. If this document and PROP-009 disagree, the PROP wins.</fact></p>
  <section title="1. What this document is">
    <p p="5"><fact id="origin-question" status="doc/done">PROP-007 shipped the workspace data model (M1.17) but deliberately left one question
open — [PROP-007 §6 question 3](../modules/vibe-workspace/PROP-007-workspace.xml#open),
the *per-member materialisation target*: when a dependency is resolved for member M,
into which member's `spec/` does its content land?</fact></p>
    <p p="6"><fact id="scope-of-answer" status="doc/done">This session answered it. The answer turned out to be far larger than picking a
directory: it is a redesign of vibevm's entire **loading model** — how a dependency's
content is materialised, how the boot sequence is composed across a workspace
hierarchy, and how an AI agent consumes it at session start. This document records
the *why* and the fork-by-fork reasoning; **PROP-009** is the contract, and it shipped.</fact></p>
    <p p="7"><fact id="workspace-arc-continuity" status="doc/done">It belongs to the workspace arc and continues
[`workspace-and-qualified-naming.xml`](workspace-and-qualified-naming.xml).</fact></p>
  </section>
  <section title="2. The problem the deferred question was hiding">
    <p p="8"><fact id="narrow-question-illusion" status="doc/done">PROP-007 §6 q3 reads as a narrow placement question. It is not.</fact></p>
    <p p="9"><fact id="flat-model-shape" status="doc/done">vibevm's boot model ([`VIBEVM-SPEC.md` §6](../../VIBEVM-SPEC.md)) is a **flat, single,
shared, mutable namespace** — `spec/boot/NN-*.md`, read in filename order, one
sequence, one entry point. It is correct for exactly one project shape: one project →
one boot sequence → one entry point.</fact></p>
    <p p="10"><fact id="workspace-breaks-lead" status="doc/done">A workspace breaks every one of those assumptions at once:</fact></p>
    <list ordered="false" p="11">
      <item><fact id="break-n-nodes" status="doc/done">**N nodes** — the root plus every member.</fact></item>
      <item><fact id="break-n-entry-points" status="doc/done">**N entry points** — a developer `cd`s into any member and opens an agent there.
  This is PROP-007's load-bearing principle: "the user works in a sub-project and
  doesn't notice it is part of something bigger."</fact></item>
      <item><fact id="break-n-boot-sequences" status="doc/done">**N boot sequences** — each entry point needs a sequence coherent *for that node*.</fact></item>
      <item><fact id="break-shared-deps" status="doc/done">**One shared dependency set** — unified resolution (PROP-007 §2.4) means one version
  of each external dependency across the whole workspace.</fact></item>
    </list>
    <p p="12"><fact id="flat-model-verdict" status="doc/done">The flat model cannot be stretched over this. It must be replaced.</fact></p>
    <p p="13"><fact id="OWNER-CONSTRAINT-NO-REWRITE" status="doc/done">The owner's hard constraint, stated at the outset: **installing a dependency must
never modify anyone's authored spec.** The owner's analogy is C++ — you do not rewrite
your `#include` directives into the literal text of the dependency's headers. Merging
a dependency's spec into the consuming spec is the broken option, and it is what a
naïve "bubble everything into the root `vibevm/vibespecs/boot/`" would amount to.</fact></p>
  </section>
  <section title="3. The owner&apos;s mental model — boot as linking">
    <p p="14"><fact id="linking-frame" status="doc/done">The owner framed the loading mechanism directly as **static vs dynamic linking**, and
that framing became the spine of the design.</fact></p>
    <table p="15">
      <tr>
        <td>C++ / the linker</td>
        <td>vibevm</td>
      </tr>
      <tr>
        <td><fact id="ROW-LINK-COMPILE" status="doc/done">Compile + link time</fact></td>
        <td><fact id="ROW-LINK-COMPILE-VIBEVM" status="doc/done">`vibe install`</fact></td>
      </tr>
      <tr>
        <td><fact id="ROW-LINK-LOAD" status="doc/done">Load + run time</fact></td>
        <td><fact id="ROW-LINK-LOAD-VIBEVM" status="doc/done">start of an AI session</fact></td>
      </tr>
      <tr>
        <td><fact id="ROW-LINK-OBJECT" status="doc/done">Object file / library</fact></td>
        <td><fact id="ROW-LINK-OBJECT-VIBEVM" status="doc/done">a package (flow / feat / stack / tool)</fact></td>
      </tr>
      <tr>
        <td><fact id="ROW-LINK-EXECUTABLE" status="doc/done">The executable</fact></td>
        <td><fact id="ROW-LINK-EXECUTABLE-VIBEVM" status="doc/done">a node's effective boot sequence</fact></td>
      </tr>
      <tr>
        <td><fact id="ROW-LINK-LOADER" status="doc/done">The dynamic loader (`ld.so`)</fact></td>
        <td><fact id="ROW-LINK-LOADER-VIBEVM" status="doc/done">the AI agent following INCLUDE pointers</fact></td>
      </tr>
      <tr>
        <td><fact id="ROW-LINK-DT-NEEDED" status="doc/done">`DT_NEEDED` entry</fact></td>
        <td><fact id="ROW-LINK-DT-NEEDED-VIBEVM" status="doc/done">an INCLUDE pointer (a `spec://` reference)</fact></td>
      </tr>
      <tr>
        <td><fact id="ROW-LINK-STATIC" status="doc/done">Static linking (`.a` copied into the binary)</fact></td>
        <td><fact id="ROW-LINK-STATIC-VIBEVM" status="doc/done">`vibe install` inlines a dependency's boot</fact></td>
      </tr>
      <tr>
        <td><fact id="ROW-LINK-DYNAMIC" status="doc/done">Dynamic linking (`.so` referenced, resolved at load)</fact></td>
        <td><fact id="ROW-LINK-DYNAMIC-VIBEVM" status="doc/done">the INCLUDE pointer stays; the agent resolves it</fact></td>
      </tr>
      <tr>
        <td><fact id="ROW-LINK-VENDOR" status="doc/done">`vendor/` / `~/.cargo/registry`</fact></td>
        <td><fact id="ROW-LINK-VENDOR-VIBEVM" status="doc/done">the materialised-dependency tree</fact></td>
      </tr>
    </table>
    <p p="16"><fact id="AGENT-IS-THE-LOADER" status="doc/done">The load-bearing consequence: **at session start, the AI agent is the loader.** Every
reference the agent resolves itself costs tool calls, and tool calls are — the owner's
words — *безумно дорого*. Static linking moves resolution to `vibe install` time (done
once, by the machine); dynamic linking leaves it to the agent (every session, by the
LLM). Exactly the C++ tradeoff: a statically-linked binary loads with no help; a
dynamically-linked one needs the loader to find and map every `.so`.</fact></p>
  </section>
  <section title="4. The model — four principles">
    <p p="17"><fact id="P1-TWO-TREES" status="doc/done">**P1 — Two trees.** A node's authored `spec/` (only the node's author writes it) and
the materialised dependencies (a separate tree, only `vibe` writes it) are physically
separate and never intermixed. Installing a dependency never touches authored `spec/`.
This is "your code vs `vendor/`". Under unified resolution a dependency is materialised
**once** for the whole workspace.</fact></p>
    <p p="18"><fact id="P2-COMPUTED-SEQUENCE" status="doc/done">**P2 — The boot sequence is computed, not assembled by hand.** Each node has an
*effective boot sequence* = inherited foundation (from ancestors, flowing down) + the
node's own authored boot + the boot of its transitive dependencies (flowing up) + user
overrides. `vibe` computes it from the unified resolution. This is the owner's
"matryoshka" — but computed directly per level from the resolution graph, not
physically copied leaf-to-root (copying drifts; computation does not). Every level is
self-contained: a session opened at any node gets a sequence coherent for that node's
subtree. The root's sequence is the union of everything; a small member's is small —
the hierarchy gives cost-scoping for free.</fact></p>
    <p p="19"><fact id="P3-INDEX-PER-ENTRY-POINT" status="doc/done">**P3 — One generated index per entry point; the agent never walks the graph.**
`vibe install` generates, for each entry-point node, the boot artifacts (§6). The
agent reads them in a flat, predictable loop — reads parallelise, collapsing latency.
No recursion, no discovery, no cycle-detection on the agent's side: `vibe` did that
once. Boot stays **pure file-reading** — the `CLAUDE.md` / `AGENTS.md` / `GEMINI.md`
redirect points at generated files; it does *not* become "run `vibe`". This preserves
the zero-dependency cross-agent property that is the whole point of VIBEVM-SPEC §6.1.</fact></p>
    <p p="20"><fact id="P4-THREE-INCLUSION-TYPES" status="doc/done">**P4 — Three inclusion types: `inline`, `static`, `dynamic`.** Declared per dependency
in the consumer's `vibe.toml`; default `static`. They are the points on the linker
spectrum (§6). *(As shipped after the 2026-07-16 rename: two types, `link = "static" | "dynamic"`,
default `dynamic`, with the third case expressed as a `dynamic` entry carrying a `when` — see the
rename note above.)*</fact></p>
  </section>
  <section title="5. The fork-by-fork record">
    <p p="21"><fact id="forks-lead" status="doc/done">Four forks were put to the owner. The options, the resolution, the reasoning.</fact></p>
    <section title="Fork 1 — the form of static boot delivery">
      <p p="22"><fact id="fork1-options" status="doc/done">Options offered: a single inlined aggregate (cheapest at boot, but duplication and
the lost-in-the-middle risk §6.4 already rejected); a resolved path index (clean, but
1 + N reads); a hybrid.</fact></p>
      <p p="23"><fact id="FORK1-REFINED-HYBRID" status="doc/done">**Resolution — a refined hybrid.** Not one of the three: a model where `inline`,
`static`, and `dynamic` *all coexist* as per-dependency inclusion types (§6), plus a
dedicated generated `STATIC.md`. The owner's reasoning: `STATIC.md` is an *emergency
priority lane*. For the highest-importance content — top-level skills, critical
disciplines — the boot text is concatenated verbatim into one file read first, so its
priority is guaranteed by *position* and does not depend on the agent performing
resolution correctly. This is the honest answer to lost-in-the-middle (§6.5): you do
not fix attention degradation by being clever about file counts; you fix it by putting
the must-not-be-missed content physically first.</fact></p>
    </section>
    <section title="Fork 2 — where materialised dependencies live">
      <p p="24"><fact id="FORK2-COMMITTED-TREE" status="doc/done">**Resolution — a committed dependency tree.** A fresh clone is bootable with no
`vibe install`; the dependencies are visible and diffable; it is consistent with the
spec-driven ethos — the spec corpus *is* the product. Plus: a `vibe` command to
regenerate a subtree of the materialised state on demand — for when dependencies are
believed stale or a previous index pass was wrong.</fact></p>
    </section>
    <section title="Fork 3 — uniform vs workspace-only">
      <p p="25"><fact id="FORK3-UNIFORM" status="doc/done">**Resolution — uniform.** A single-package project is a degenerate (zero-member)
workspace; one loading model everywhere. Consistent with `Workspace::discover`, which
already degenerates cleanly to "just this one node". The cost — every existing
project's layout migrates — is acceptable: vibevm is pre-release, and M1.17's
no-legacy hard break already set the precedent.</fact></p>
    </section>
    <section title="Fork 4 — milestone scope">
      <p p="26"><fact id="FORK4-UNIFIED-VIEWS" status="doc/done">**Resolution — boot + effective spec, unified.** The boot index and the `vibe build`
effective spec (VIBEVM-SPEC §4.6) are the same idea: a computed, layered, materialised
view of the workspace. PROP-009 specifies one *computed-view engine*; the boot index
("what to read at session start") and the effective spec ("the full merged corpus for
build") are two views it emits.</fact></p>
    </section>
  </section>
  <section title="6. The three inclusion types — the refined Fork-1 answer in detail">
    <p p="27"><fact id="inclusion-types-lead" status="doc/done">Each dependency in a consumer's `vibe.toml` carries an inclusion type (working syntax
of this session: `link = "inline" | "static" | "dynamic"`); the default was `static`. At `vibe install`
time, for each entry-point node `vibe` generates:</fact></p>
    <list ordered="false" p="28">
      <item><fact id="GEN-STATIC-MD" status="doc/done">**`STATIC.md`** — the verbatim concatenation of every `static`-typed contribution in
  the node's effective boot, in priority order. Read first; one read; maximum attention
  weight. The emergency lane — used sparingly, for top-level skills and critical
  disciplines. Generated only when the node has inline contributions (shipped name:
  `static` contributions, carried by the `vibe:static` markers inside `STATIC.md`).</fact></item>
      <item><fact id="GEN-INDEX-MD" status="doc/done">**`INDEX.md`** — the ordered, resolved manifest of the rest of the boot sequence.
  `static` entries appear as resolved file paths the agent reads directly (a flat,
  parallelisable loop). `dynamic` entries appear as INCLUDE pointers the agent resolves
  at boot.</fact></item>
      <item><fact id="SESSION-START-ORDER" status="doc/done">Session-start order: `CLAUDE.md` → `STATIC.md` → `INDEX.md` and the files it names.</fact></item>
    </list>
    <p p="29"><fact id="cost-profile-lead" status="doc/done">Cost profile:</fact></p>
    <table p="30">
      <tr>
        <td>Type</td>
        <td>Reads at boot</td>
        <td>Content on disk</td>
        <td>Use</td>
      </tr>
      <tr>
        <td><fact id="ROW-COST-INLINE" status="doc/done">`inline` (ships as `link = "static"`)</fact></td>
        <td><fact id="ROW-COST-INLINE-READS-AT-BOOT" status="doc/done">~1 (already in `STATIC.md`)</fact></td>
        <td><fact id="ROW-COST-INLINE-CONTENT-ON-DISK" status="doc/done">duplicated (bounded — few items)</fact></td>
        <td><fact id="ROW-COST-INLINE-USE" status="doc/done">critical disciplines, top-level skills</fact></td>
      </tr>
      <tr>
        <td><fact id="ROW-COST-STATIC" status="doc/done">`static` (ships as `link = "dynamic"`)</fact></td>
        <td><fact id="ROW-COST-STATIC-READS-AT-BOOT" status="doc/done">1 + N (N parallelisable)</fact></td>
        <td><fact id="ROW-COST-STATIC-CONTENT-ON-DISK" status="doc/done">lives once</fact></td>
        <td><fact id="ROW-COST-STATIC-USE" status="doc/done">the default — ordinary dependencies</fact></td>
      </tr>
      <tr>
        <td><fact id="ROW-COST-DYNAMIC" status="doc/done">`dynamic`</fact></td>
        <td><fact id="ROW-COST-DYNAMIC-READS-AT-BOOT" status="doc/done">1 + N + graph-walk</fact></td>
        <td><fact id="ROW-COST-DYNAMIC-CONTENT-ON-DISK" status="doc/done">lives once</fact></td>
        <td><fact id="ROW-COST-DYNAMIC-USE" status="doc/done">conditional / context-gated boot</fact></td>
      </tr>
    </table>
    <p p="31"><fact id="dynamic-is-lazy-pull" status="doc/done">`dynamic` is, mechanically, the subskill `lazy-pull` delivery mode (PROP-003 §2.5) —
the loading model generalises subskill delivery rather than inventing a parallel axis.</fact></p>
  </section>
  <section title="7. Consequences and findings">
    <list ordered="false" p="32">
      <item><fact id="FINDING-NUMBERING" status="doc/done">**Numbering.** The `NN-` prefix namespace (10–89, author-chosen) cannot survive a
  workspace and is already admitted provisional (§6.5). In the computed model `vibe`
  owns the order in the generated artifacts; a package author declares only a
  *category* (the existing range bands — foundation / flow / stack / user-override —
  become categories) and optionally a coarse early/late hint. Prefix collisions become
  impossible by construction.</fact></item>
      <item><fact id="FINDING-MIRROR-BREAKAGE" status="doc/done">**Mirror-layout breakage.** VIBEVM-SPEC §13.1's mirror layout — source path = target
  path — works today only because a dependency always lands at the same path in every
  project. Moving dependency content into a separate tree breaks that; a package's
  internal cross-references (a boot snippet pointing at its own protocol document) must
  become package-relative or `spec://` URIs, rewritten by `vibe` at materialisation.</fact></item>
      <item><fact id="FINDING-PUBLISH-REGEN" status="doc/done">**Published-copy regeneration.** A package published by `vibe workspace publish` is
  consumed standalone — its boot index must be regenerated for the published shape,
  where dependencies are registry-resolved and version-pinned rather than path-sourced.
  This is exactly PROP-007 §2.5's dual-form `{ path, version }`; publish staging gains
  an index-regeneration step.</fact></item>
      <item><fact id="FINDING-DOGFOOD" status="doc/done">**vibevm dogfoods itself.** The vibevm repository is itself a vibevm project;
  PROP-009 changes how *this* repository boots. `vibevm/vibespecs/boot/00-core.xml` and
  `vibevm/vibespecs/boot/90-user.xml` stay user-owned authored boot; the generated `STATIC.md` /
  `INDEX.md` join them. The migration is part of the milestone.</fact></item>
    </list>
  </section>
  <section title="8. What this supersedes and parks">
    <list ordered="false" p="33">
      <item><fact id="SUBSUMES-INSTALL-BUILD" status="doc/done">**Workspace-aware `vibe install` / `vibe build`** (PROP-007 §9.3, §6 q3) is no longer
  a separate deferred item — it is *subsumed*: it becomes the install/build half of
  PROP-009.</fact></item>
      <item><fact id="parks-version-workspace" status="doc/done">**`version = { workspace = true }`** (PROP-007 §6 q4) and the **publish-signalling
  polish** (`--archive` etc., PROP-007 §9.3) are parked behind PROP-009 — recorded, not
  dropped.</fact></item>
      <item><fact id="prop-008-unaffected" status="doc/done">**PROP-008** (qualified naming) is unaffected; it still follows PROP-005 (index).</fact></item>
    </list>
  </section>
  <section title="9. Session log">
    <list ordered="false" p="34">
      <item><fact id="session-log-2026-05-21" status="doc/done">**2026-05-21.** Session restored from `CONTINUE.md` + `vibevm/vibespecs/WAL.xml`. The owner
  reopened PROP-007 §6 q3 (the materialisation target). The discussion established
  that the question is a loading-model redesign, not a directory choice; produced the
  linker-model spine (§3), the four principles (§4), and the four-fork resolution
  recorded in §5. PROP-009 and its implementation milestone (M1.18) deferred to the
  contract-writing step. Out of band, a standing test-environment misdiagnosis was
  corrected — `os error 740` on `cargo test -p vibe-install` is Windows UAC installer
  detection (the test binary's name contains "install"), not Windows Defender; see the
  WAL.</fact></item>
    </list>
  </section>
  <section title="10. Pointers">
    <list ordered="false" p="35">
      <item><fact id="ptr-prop-009" status="doc/done">[PROP-009](../modules/vibe-workspace/PROP-009-loading-model.xml) — the contract; shipped M1.18.</fact></item>
      <item><fact id="ptr-prop-007" status="doc/done">[PROP-007](../modules/vibe-workspace/PROP-007-workspace.xml) — the workspace data model; §6 q3 is the question this answers.</fact></item>
      <item><fact id="ptr-workspace-naming" status="doc/done">[`workspace-and-qualified-naming.xml`](workspace-and-qualified-naming.xml) — the preceding design session.</fact></item>
      <item><fact id="ptr-vibevm-spec" status="doc/done">[`VIBEVM-SPEC.md`](../../VIBEVM-SPEC.md) — §6 (boot directory model), §4.2 (layout), §4.6 (effective spec), §13.1 (mirror layout).</fact></item>
      <item><fact id="ptr-prop-003" status="doc/done">[PROP-003 §2.5](../modules/vibe-resolver/PROP-003-dep-evolution.xml) — subskills and delivery modes.</fact></item>
    </list>
  </section>
</spec>
