<?xml version="1.0" encoding="UTF-8"?>
<spec xmlns="https://vibevm.org/spec/1">
  <title id="root">Design rationale: once-each lane composition — the aggregator double-emission (B-006)</title>
  <status stage="spec" state="done" comment="B-006 design APPROVED by the owner 2026-08-04 («согласен с твоими рекомендациями a1 b1 c1») — A1 compose-time once-each elision, B1 provenance stub without #use, C1 the contract landing (PROP-009 §2.3 + stale-interim shed, PROP-038 §2.1 cross-reference, PROP-035 §8 per-node rider). Normative landing: the §6 PROP edits; implementation: the §8 worker cut"/>
  <p p="1"><fact id="companion-line" status="spec/work">**Companion to:** BACKLOG.md B-006 (closed by `9f79acf1`) (the commissioning entry), [PROP-038](../modules/vibe-workspace/PROP-038-hybrid-boot-linking.xml) (the hybrid linker whose two write paths collide here), [PROP-009 §2.3](../modules/vibe-workspace/PROP-009-loading-model.xml#artifacts) (the lane contract the fix touches), [PROP-035 §8](../modules/vibe-workspace/PROP-035-spec-compiler.xml#pipeline) (the qualify phase the rider refines), and [`deterministic-loading-aliasing.xml`](deterministic-loading-aliasing.xml) (B-011 — whose qualification made this duplicate mechanically visible instead of silent).</fact></p>
  <p p="2"><fact id="authority-line" status="spec/work">**Authority:** non-normative proposal. On approval it lands as PROP edits (§6) and this document stays as the lore behind them.</fact></p>
  <section id="problem" title="1. The problem, measured on today&apos;s lane">
    <p p="3"><fact id="problem-shape" status="spec/work">The host's `vibevm/vibespecs/boot/STATIC.xml` carries the git commit-rules family **twice**. Once as four direct contributions — each member's own boot snippet, qualified under its own origin (`STATIC.md:1038–1261`). And once more *nested inside* the `git-practices` contribution (`:1262–1584`, **323 lines**): the umbrella has no boot snippet of its own, so the emitter substituted its **compiled unit artifact** (`vibedeps/flow-git-practices/0.1.0/spec/boot/STATIC.md`) as the contribution body — an artifact that, per the per-unit compiler's own law, already contains the four members compiled in. Nine `vibe:static` provenance markers for a five-package family.</fact></p>
    <p p="4"><fact id="problem-double-qualify" status="spec/work">B-011's qualification turned this from a silent duplicate into a loud, measurable one — and added an artefact of its own on top: the nested copies arrive **already qualified** under their member origins (the unit artifact is itself a compiled lane), and the host-level qualify pass then re-prefixes them under the umbrella's origin, minting double-qualified labels of the form `org-vibevm-world--git-practices--org-vibevm-world--git-atomic-commits--&lt;TAIL&gt;` — **164 occurrences**, each honestly recorded in the tombstone as a same-origin repeat (e.g. `STATIC.md:453`). The umbrella's own nested resolution preamble and tombstone table ride along as body text (`:1284`). Nothing collides — B-011 guarantees that — but the most expensive reader in the project pays ~320 duplicated lines at every session start, and the labels of one member text answer to two names.</fact></p>
    <p p="5"><fact id="problem-falsified-claim" status="spec/work">The shape falsifies a shipped package's sentence from the host side: `git-attribution-policy` states its policy lives «in exactly one always-loaded place (the boot snippet this package installs)». It installs exactly one; the host's compiler emits two. Wave 6 routed that obligation to the host on this evidence (the B-006 filing), and the once-each dedup law the artifact violates is already recorded — PROP-038 §2.1 `##UNIT-SELF-CONTAINED` promises every unit's lane carries its zone «in dependency order, **once each**» (the PROP-034 invariants applied within the unit), and the host root is a unit like any other.</fact></p>
  </section>
  <section id="mechanism" title="2. The mechanism, precisely">
    <p p="6"><fact id="mechanism-two-sources" status="spec/work">Two independent composition sources each emit a copy, and nothing reconciles them:</fact></p>
    <list ordered="true" p="7">
      <item><fact id="MECH-CLOSURE-WALK" status="spec/work">**The node's closure walk.** `node_dependency_boot` (`crates/vibe-workspace/src/install/bootgen.rs:284–301`) walks the root's `requires` closure breadth-first; the root's `static-transitive` edge to `redbook` forces the whole subtree static (`bootgen.rs:279`, `:339–341`), so **every** boot-bearing member — including all four git flows — becomes its own static entry with its own snippet path.</fact></item>
      <item><fact id="MECH-UNIT-SUBSTITUTION" status="spec/work">**The unit-artifact substitution.** The same walk, reaching a dependency that *statically links a child* (`with_static`), replaces its contribution path with the dependency's compiled `STATIC.md` (`bootgen.rs:323–328`, citing PROP-038 §2.1: read the whole zone through the unit artifact). `git-practices` is exactly that case — no snippet of its own, four static children (the members' `[boot_snippet] link = "static"` suggestions) — so its entry embeds the unit artifact, members included.</fact></item>
    </list>
    <p p="8"><fact id="mechanism-when-each-is-right" status="spec/work">Each source is right somewhere. The substitution is **correct for a `dynamic` edge** — an `INDEX.md` reference is read by-reference, the parent never walks inside, and pointing it at the unit artifact is the only way to load the whole zone (`hybrid_emit.rs`, `dynamic_target_path`). The closure walk is correct for the static lane. They are **both applied** to a static entry whose zone the walk also covers — that conjunction is the bug, not either mechanism alone.</fact></p>
    <p p="9"><fact id="mechanism-prior-stops" status="spec/work">Two prior tasks hit this and stopped for a ruling rather than pick a side silently: DRIFT-029 (asked to suppress per-unit artifact writes; contradicted PROP-038 §2.1 — review marker at `hybrid_emit.rs:148`) and DRIFT-030 (measured that counting the entry-point node in the hoist counter clears the aggregator's copy **but the root then holds the member twice** — once from the closure walk, once from `append_hoisted`; «which mechanism owns the dedup is a design question», review marker at `bootgen.rs:89`). This design is that question, put to the owner.</fact></p>
  </section>
  <section id="solution" title="3. The design in one paragraph">
    <p p="10"><fact id="solution-once-each" status="spec/work">**One rule, applied at compose time: a node's static lane emits each package's text once.** Concretely: when the composed entry set is known, a static entry that would embed a `with_static` package's unit artifact is checked against its zone — **if every boot-bearing member of that package's static zone is already present as its own static entry of the same composition, the aggregate entry is elided**: in its place the lane keeps a generated provenance stub (the umbrella's marker comment plus one sentence: its zone is emitted member-by-member in this lane). If even one zone member is *not* individually present as a static entry (e.g. it resolved `dynamic` at node level, so the unit artifact is the only static carrier), the substitution stands as today — the elision never drops coverage, it only removes a proven second copy. The unit artifacts under `vibedeps/` are not touched: they keep serving dynamic consumers and standalone unit reads exactly as PROP-038 §2.1 mandates; hoisting (§2.4–2.5) is not touched; the read-set is not involved. The double-qualification dies with the duplicate, because the umbrella body never enters the qualify pass.</fact></p>
    <p p="11"><fact id="solution-why-not-hoist" status="spec/work">**Why not the hoist route.** Making `hoist::soft_static_pulls` count entry-point nodes as pullers *does* degrade the aggregator's unit to `#use` markers — DRIFT-030 measured it — but at the price of (i) the root double-write it also measured (closure walk + `append_hoisted` both emit the member; a second dedup is needed anyway), (ii) a world-wide blast radius: with the root counted, **every** package pulled by `redbook` plus the root scores two pullers, so effectively the whole installed world flips to `shared` — every unit artifact under `vibedeps/` is rewritten to `#use` markers and the root lane is rebuilt through the hoist path, and (iii) semantics: hoisting exists for *sharing across consumers*, not for a consumer that already contains the zone. The narrow fix is the composition rule; the hoist counter stays package→package as shipped.</fact></p>
    <p p="12"><fact id="solution-why-not-suppress" status="spec/work">**Why not «the umbrella contributes nothing» unconditionally.** Dropping the substitution for every static entry (always use the own snippet, `None` for snippetless aggregators) is simpler — but it silently changes the semantics of a static edge to a zone whose members resolve `dynamic` at node level: PROP-038 §2.2's recursion says a static edge to `X` compiles `X`'s zone in, and in that (today hypothetical, grammar-legal) topology the unit artifact is the only carrier honouring it. The conditional elision preserves §2.2 exactly and fixes only the proven-duplicate case.</fact></p>
    <p p="13"><fact id="solution-owner-probes" status="spec/work">**The owner's two hardening probes (2026-08-04, design review), answered in the rule.** *(i) Mixed consumers* — several packages pulling the aggregator through a mix of `static` / `static-transitive` / `static-hard`: the closure walk emits **one entry per package identity** regardless of consumer count and path mix, the single-version invariant (PROP-038 §2.6) makes every copy byte-identical, and the decision is a pure function of the entry set — so the verdict is order- and mix-independent. This probe also surfaced the де-substitution refinement: a covered entry whose package ships its **own** snippet reverts to that snippet (elision-to-stub would have dropped a snippet-bearing aggregator's own text); the stub is only for snippetless umbrellas. *(ii) A package with own code plus widely-shared static libs* — full coverage de-substitutes and the shared libs dedup through their individual entries serving every consumer at once; **partial** coverage conservatively keeps the whole unit artifact, so a present member is carried twice — accepted, because composition only chooses paths and never rewrites unit artifacts; deduplicating a shared member *inside* unit artifacts is hoisting's job (§2.4–2.5: a hoisted member becomes a `#use` marker in every sharing unit, already implemented in `zone_to_effective`), and the undercounting hoist counter is the recorded DRIFT-030 trigger, deliberately out of this slice (the rejected fork A2). Both probes are named fixtures in the worker cut (Т3, Т4, Т8).</fact></p>
  </section>
  <section id="rider" title="4. The rider — per-node qualify for cross-origin closures (W3&apos;s named follow-up)">
    <p p="14"><fact id="rider-what" status="spec/work">The B-011 implementation qualifies **each contribution as a whole under the entry's origin** (PROP-035 §8 `##PIPE-QUALIFY`: «rewrite each contribution's label definitions»). That is exact for a `simple` snippet, and wrong in general for any body that splices **cross-origin** content: a `normal` entry's compiled closure can contain nodes `#use`d from other packages, and today they would qualify under the *entry's* origin — mis-attributed provenance, the same class as the umbrella's double-prefix. W3's report named this «deferred to the B-006 follow-up». The refinement: the qualify phase runs **per node, under each node's own origin** (the compiler knows every spliced node's source package). For the git family this becomes moot once §3 elides the umbrella; for `normal` closures it is the honest general form. One sentence of PROP-035 §8 moves («each contribution's» → «each node's, under the node's own origin»); measured population of affected cross-origin closures in today's tree: the git umbrella itself and zero `normal` static entries — the refinement is cheapest now, before one exists.</fact></p>
  </section>
  <section id="forks" title="5. The forks the owner is asked to rule on">
    <p p="15"><fact id="forks-tree" status="spec/work">Three forks, the boss's recommendation first in each:</fact></p>
    <list ordered="false" p="16">
      <item><fact id="FORK-DEDUP-OWNER" status="spec/work">**(A) Who owns the dedup.** **(A1, recommended) compose-time elision at the node** (§3): minimal perimeter (`vibe-workspace` composition), `vibedeps/` untouched, hoisting untouched, §2.2 preserved, the observed duplicate provably removed. (A2) the hoist route: count entry-points as pullers + reconcile the root double-write — the DRIFT-030 measured trap, world-wide unit rewrites, two mechanisms changed to fix one site. (A3) tolerate as filed — refused by the campaign's own mandate: `duplication` is a target defect class, and this instance is the priciest reading surface in the project.</fact></item>
      <item><fact id="FORK-STUB-FORM" status="spec/work">**(B) What stands where the umbrella's text stood.** **(B1, recommended) a generated provenance stub** — the `vibe:static`-style marker comment naming the origin plus one sentence «zone emitted member-by-member in this lane», **no `#use` directive**: a `#use spec://…/git-practices` would point the reader's mandatory-read machinery at the unit artifact — a *different file* whose content is exactly the duplicate being removed, and the read-set (`{specpath, content_hash}`) would not dedup it against the members' snippets. (B2) the §2.5 `#use` marker for visual uniformity with hoisting — carries that re-read trap; choose only if the graph-edge-in-lane property is judged worth it.</fact></item>
      <item><fact id="FORK-CONTRACT-LANDING" status="spec/work">**(C) The contract landing.** **(C1, recommended)** PROP-009 §2.3 `##ARTIFACT-STATIC-MD` gains the once-each sentence («the lane emits each package's contribution once; an entry whose static zone is fully present as individual entries of the same lane is elided to a provenance stub») — and sheds, in the same edit, its stale interim tail «*Until B-011's implementation lands, the shipped renderer still concatenates verbatim*» (B-011 landed 2026-08-04; the sentence now describes a renderer that no longer ships). PROP-038 §2.1 gains one cross-reference sentence (the unit artifact serves dynamic consumers and standalone reads; a static consumer that compiles the zone member-wise elides it). PROP-035 §8 changes only under the §4 rider. (C2) leave the PROPs silent and fix only the code — refused by the house rule: the lane's observable shape is contract surface, and a silent divergence is how B-006 got filed.</fact></item>
    </list>
  </section>
  <section id="normative" title="6. What becomes normative on approval">
    <p p="17"><fact id="normative-list" status="spec/work">The §5-C1 edit list verbatim (PROP-009 §2.3, PROP-038 §2.1, and — with the rider — PROP-035 §8's per-node sentence), applied by the boss (spec authoring is never delegated) before the implementation packet is cut. `BACKLOG.md` B-006's acceptance restates as §7's measurements. No registry anchors ride this build: none of the six deferred rows names B-006, so the landing closes the backlog entry and the wave-6 host obligation — the re-judge surface is the `git-attribution-policy` claim, already routed to the host.</fact></p>
  </section>
  <section id="acceptance" title="7. Acceptance, measurable">
    <p p="18"><fact id="acceptance-list" status="spec/work">On the regenerated lane: **(i)** each git-family member appears exactly once — five `vibe:static org.vibevm.world/git-*` markers total (four members + the umbrella's stub), down from nine; **(ii)** zero double-qualified labels — `grep -c -- "--git-practices--org-vibevm-world--"` drops 164 → 0; **(iii)** the tombstone carries no same-origin repeat rows; **(iv)** the lane loses ~320 lines; **(v)** `DocTree::duplicate_anchors() == []` holds as before (B-011's gate); **(vi)** the dynamic-member topology keeps the substitution (the §3 guard, fixture-tested); **(vii)** panel green, `INDEX.md` byte-stable. Property test for the rider: a `normal` closure splicing a cross-origin node qualifies that node under the node's own origin.</fact></p>
  </section>
  <section id="implementation" title="8. Implementation shape (after the ruling — the worker cut)">
    <p p="19"><fact id="impl-slices" status="spec/work">Two native collaboration packets with disjoint perimeters, per the transport law (self-verify includes `cargo clippy -p &lt;crate&gt; --all-targets -- -D warnings`): **(W-A)** the composition elision — `crates/vibe-workspace/src/install/bootgen.rs` + `install/bootgen/hybrid_emit.rs` + `boot.rs` seam types + fixture tests (the vibevm shape: root → `static-transitive` aggregator → members; the dynamic-member guard; the golden lane); **(W-B)** the per-node qualify rider — `crates/vibe-spec/src/pipeline.rs` (`compile_normal_entry` emit phase) + `crates/vibe-workspace/src/boot_artifacts.rs` splice seam + a cross-origin fixture. Boss work: the §6 PROP edits, host lane regeneration (`vibe install --assume-yes`), gates, commits, and the two DRIFT review markers (`hybrid_emit.rs:148`, `bootgen.rs:89`) retired in the same landing.</fact></p>
  </section>
</spec>
