VibeVM
Contents
On this page
ru
Publisher
org.vibevm.core
Version
1.0.0latest
Adapts
org.vibevm.core/vibevm-docs
Audiences
user, author
Reading time
7 min
Rendered
Read aloud
never

Видимость зависимостей: public, private и друзья

01У пакета, от которого вы зависите, есть собственные зависимости, и они тоже могут дотянуться до вашего проекта. Дотянутся ли, решается там, где объявлена каждая зависимость, построчно: получают все, не получает никто или только проекты, которые назвали объявляющий пакет другом. Эта страница объясняет три метки, дружбу, которая открывает среднюю из них, что в результате оказывается в вашем дереве и как спросить vibe, почему пакет тут есть или почему его нет.

02

Три метки на требовании

03Каждая строка под [requires.packages] — ребро от вашего пакета к тому, который она называет, и ребро несёт необязательную метку access. Метка — слово объявляющего пакета о его собственной зависимости: как далеко вверх ей можно просачиваться, к проектам, которые зависят от объявляющего пакета.

04 Each [requires.packages] edge gains an optional access property with three values — the provider-side seepage mark on the edge P → Q, declared by P about its own dependency Q:
05[requires.packages]
"org.example/style" = "^1.0"
"org.example/wal" = { version = "^2.0", access = "private" }
"org.example/inner" = { version = "^1.0", access = "friends-only" }

06public — умолчание, и писать его не нужно: зависимость достигает каждого потребителя над вами, как бы высоко он ни стоял, и никому не нужно ничего включать. Это правильная метка для всего, на чём строится ваш собственный текст, и для участников коллекции.

07 access = "public"the default. Q seeps through P to every consumer above, transitively along the whole hierarchy, with no opt-in. For edges whose target is part of the declarant's substance for all consumers — a collection's members, a stack's core, and every ordinary «my text builds on this» edge.

08private останавливает зависимость у вашей двери. По ребру идут, только когда ваш пакет сам корень установки, как в вашем собственном чекауте. Это метка для инструментов и для дисциплин, которые определяют, как вы работаете, а не что вы поставляете.

09 access = "private"Q does not seep through P at all: the edge is traversed only when P itself is the consumer root (§4.4 — the dev world). An implementation detail in the strictest sense — the explicit mark for WAL-class disciplines and dev tooling.

10friends-only стоит между ними. Зависимость достигает только потребителей, чьё замыкание друзей содержит ваш пакет: тех, кто намеренно назвал вас другом, напрямую или через своего друга.

11 access = "friends-only"Q seeps through P only into consumers whose friend closure contains P (§2.4): those who deliberately named P (directly or transitively) a friend. The curated middle.

12Поскольку присутствие течёт по умолчанию, долг автора — сужать намеренно. Помечайте private каждое ребро, которое не входит в то, что вы предлагаете, и friends-only — то, на чём должен строиться только ваш ближний круг. Каждое публичное ребро стоит вашим потребителям бюджета чтения, и лок-файл делает этот счёт видимым.

13 Authoring norm for narrowing marks (the JPMS community rule, transposed and then inverted by the public default): since presence flows by default, the author's duty is to narrow deliberately — mark private every edge that is not part of your consumable substance (WAL-class disciplines, dev tooling, heavy optional companions), and friends-only what only your inner circle should build on. Aggregator-style «one edge pulls the world» is lawful for collections, whose members are their declared substance (§4.6); everyone else answers for every public edge with its lane cost (§7 measurements make the bill legible). Advisory, policed by the §7 lints, enforced by nobody — strict-deps culture with the autofix command in place of ceremony.

Дружба: согласие потребителя

14Дружбу объявляет потребитель, и никогда она не подразумевается. На ребре friend = true говорит: «я вступаю в дружбу с этим пакетом»; в секции [visibility] friends = ["org.example/inner"] говорит то же о пакете, который вы напрямую не требуете. По умолчанию false: обычное ребро берёт пакет, а не его ближний круг. Присутствие щедро, дружба скупа, и два умолчания различаются намеренно.

15 Per-edge friend = true|false (default false — owner re-ruled 2026-08-23). Friendship is a raised privilege — receiving a target's gated substance — and raised privileges are not granted where they may never be used: an ordinary edge takes the package, not its inner circle. friend = true is the explicit opt-in; the original default-true belonged to the earlier one-field paradigm and is retired with it. With the public presence default (§2.2) the two defaults form the deliberate asymmetry: presence is generous, friendship is stingy — the ordinary world works with zero ceremony, the curated world opens only by explicit word.

16Метка friends-only на вашем собственном ребре подразумевает дружбу с пакетом, который оно называет, так что цепочка друзей работает от одной метки на переход. Напишите рядом friend = false, когда хотите доставить пакет своему кругу, не входя в его круг сами.

17 The implication — owner-ratified (F10, 2026-08-23): a friends-only mark implies friend = true on its own edge. Vouching for a package as part of your substance while standing in no relation to it is incoherent — and under the strict friend = false default, a friends-only chain would otherwise need two marks per hop, where forgetting the second silently kills the chain. With the implication, the owner's A → B → C → D chain works from one mark per hop, exactly as originally intended; an explicit friend = false beside a friends-only mark overrides the implication and yields the lawful no-vouch cell of ##ACCESS-FRIEND-MATRIX (terminal delivery to the circle) — no lint, it is a real intent.

18Друг ничего не объявляет о том, что получает. Когда вы дружите с пакетом, всё, за что он ручается, приходит без строки в вашем манифесте, в версиях, которые выбрал поручитель, и ребра friends-only этих пакетов открываются в свою очередь. В тот момент, когда ваш собственный текст начинает строиться на одном из них, объявите собственное прямое ребро: транзит говорит «здесь, потому что на этом стоит друг», а не «моё».

19 A friend declares nothing about the vouched content — by design. When R befriends P (one explicit line: friend = true on its P edge, or a friends entry), everything P vouches for arrives with no mention in R's manifest: P's friends-only edge admits Q (rule (3)), the grow rule puts Q into C(R), and Q's own friends-only edges then open too — recursively, the owner's original transitivity requirement. Version choice for Q stays with the voucher (P's constraint on its own edge) — the vouched set is a bundle P tested, not a menu R assembles. This is the standard re-export semantics of JPMS requires transitive (implied readability chains), Bazel deps + exports*, and Gradle api — a dependency on P is a dependency on «P with everything P stands on». Control never leaves the payer: the grant is explicit (the false default), unfriend/per-edge exclude prune point-wise, and the lock-diff + vibe why make every transit arrival legible. The hygiene norm transposes from Bazel strict-deps: transit covers «Q is here because P stands on it»; the moment R's own text starts building on Q, R declares its own direct edge.

20Две метки независимы и указывают в противоположные стороны, поэтому сочетаются. Публичное ребро с friend = true доставляет пакет всем над вами и открывает его двери friends-only только для вас; эта дружба дальше не едет. Передавать дружбу дальше — ровно то, что делает метка friends-only.

21 access and friend compose independently on one edge (owner-confirmed 2026-08-23: «access и friend разные понятия»). The two marks point in opposite directions, so their product is well-defined. The default shape — public presence, no friendship — is plain delivery: «Q reaches everyone above me; I take none of its gated substance». Adding friend = true to a public edge reads: «and for myself I enter friendship with Q, so Q's friends-only doors are open in my own perspective». That friendship does not travel onward through a public edge — re-exporting friendship is exactly what the friends-only mark does (##PUBLIC-GIVES-PRESENCE-NOT-FRIENDSHIP) — so in another root's closure a public edge contributes presence and nothing more. The remaining corner — «deliver publicly and vouch friendship onward» in a single edge — is deliberately inexpressible: a consumer that wants Q's gated substance opts in with its own friends line, which is the payer-decides invariant.

Секция visibility, unfriend и exclude

22Всё, что касается пакета в целом, а не одного ребра, живёт в одной секции, [visibility], одинаковой для проекта и для пакета: friends, unfriend, allow-friends и ignore-concept-warnings. Рядом с ней стоит таблица верхнего уровня [override], описанная ниже.

23 The node-level vocabulary lives in one role-blind [visibility] sectionfriends, unfriend, allow-friends (§2.8), ignore-concept-warnings (##CONCEPTS-GATE-SOFTENED) — plus the sibling top-level [override] table (§2.9). One section serves both manifest roles by construction (PROP-024 equipotence): no field is duplicated between [project] and [package].
24[visibility]
friends = ["org.example/inner"]
unfriend = ["org.example/noisy"]
allow-friends = ["org.example/partner"]

25unfriend убирает названные пакеты из дружб, которые вы передаёте дальше. Они по-прежнему приходят на ваш уровень, когда их допускает ребро, но никто не видит их вашими друзьями через вас. Другой пакет в том же дереве всё ещё может с ними дружить; обрезка только ваша.

26 unfriend = ["group/name", …] (node-level) removes the named packages from the declaring node's grants(…) — and therefore from every friend closure as seen through that node. The unfriended package «притянется, но будет явно исключён из цепочки транзитивности внутренних друзей»: still usable at the declaring level (its edge, if any, still traversable by its own access), just never re-exported as a friend through the declarant. Node-scoped by owner law: «они выбрасываются из замыкания ТОЛЬКО с точки зрения той ноды, которая объявила их unfriend — а какой-нибудь другой пакет в иерархии может нормально включить их в замыкание» — another node's friends-only chain delivers the same package untouched. The name unfriend is owner-ratified (F2, 2026-08-23); the property list's enemy is retired.

27exclude, записанный на ребре, — другая обрезка: названные пакеты вырезаются из каждой цепочки, проходящей через это ребро, как бы глубоко они ни были, даже там, где они публичны. Другой путь всё ещё может их доставить, и тогда они присутствуют через него. Исключение может только сузить то, что предоставили объявляющие пакеты, и никогда не расширить, поэтому объявить его может любой пакет.

28 exclude = ["group/name", …] (per-edge) kills the named packages in every chain passing through the declaring edge — «исключены из цепочки транзитивных подключений вообще, даже если внутри они объявлены как public». Maven-exclusions semantics, owner-ratified (F4, 2026-08-23: «exclude per-ребро Maven-style. Можно per-ребро делать глубокие эксклюды по иерархии — это не глобальный deny-list, это сужение в рамках поддерева»): the pruning reaches arbitrarily deep, but only within this edge's subtree; a different path still delivers the package, and then it simply exists in E(R) via that path — classic diamond behaviour, no global veto. Exclusion is pure subtraction — it can only narrow what providers granted, never widen — which is why any node may declare it as part of shaping its own delivery; the expansive counterpart is F9's root-only override, which may also re-house this syntax (the semantics here stand either way).

29Пакет может и сказать, кому разрешено с ним дружить. Отсутствующий allow-friends значит «кому угодно»; пустой список запечатывает пакет, так что его закрытое содержимое существует только в его собственном чекауте; список называет точный круг. Проверка ложится на того, кто объявляет дружбу: объявление, которого пакет не разрешает, — предупреждение, а не ошибка, и замыкание там не растёт.

30 Owner-ordered design (F8, 2026-08-23: «спроектируй механизм allow-friends… похоже на возможность построить exhaustive замыкание sealed classes»). A provider G may declare, node-level, who is permitted to enter friendship with it — the Java-sealed/permits shape transplanted onto the friendship relation (design ratified — «годится»):
31 Three states: field absent — friendship is open, anyone's grant works (the default, today's semantics); empty list — sealed: nobody enters, the gated substance exists only in G's own dev world; a list — exactly the named circle.
32 The check sits on the grant giver: a grant N → G (an explicit friend = true edge, a friends entry, or an F10-implied one) participates in any closure only if allow-friends(G) is absent or covers N. A friends-only re-export hop F → G in C(R) likewise requires F permitted by G. A rejected grant is a warning, never an error (the §5 unknown-target precedent) — the closure simply does not grow there.

33Печать закрывает дружбу, а не доставку. Запечатанный пакет всё равно приходит туда, куда его доставляет ребро friends-only; закрытым остаётся его собственный ближний круг, а отвергнутое объявление попадает в отчёт. vibe friends org.example/partner печатает полную картину по одному пакету: открыт, запечатан или назван круг, кто с ним дружит, какие объявления он отвергает и входит ли он в ваше замыкание.

34 The seal gates friendship, never delivery (pinned at the W6 landing). A sealed G still arrives wherever a declarant's friends-only edge delivers it — the declarant owns its own edge and could as well have marked it public; what the seal closes is entry into G's circle: a rejected grant keeps G out of every closure, so G's own friends-only inner content stays shut and the grant surfaces as a RejectedGrant warning. The observable difference between sealed and unsealed is always the inner content and the diagnostics, never the presence of G itself. Proven end-to-end by cli_visibility_power.rs (unseal and exact-circle scenarios).

Починить ребро, которым вы не владеете

35Иногда нужная вам метка стоит на ребре, которым вы не владеете: участник коллекции пометил зависимость как private, а она нужна вашим потребителям, или пакет запечатался от вас. Таблица [override] переписывает чужие ребра, и она законна в любом манифесте, в корне или ниже. Агрегатор пользуется ею, чтобы перекроить ребро участника для всех своих потребителей, так же как курирует свою доставку через exclude.

36 Owner-ruled (2026-08-23): override is lawful in any manifest, not only the root («разрешён не только в корневом манифесте, а где угодно»). Any node N may carry an [override] table whose entries rewrite foreign edges — their access, friend, presence (exclude = true), or a target's allow-friends — and the rewrite acts wherever N stands on the chain: an aggregator repairs or reshapes a member's edge for all of its own consumers, exactly as it curates its delivery with exclude. The threat model follows the owner's earlier ruling: a deliberate break-in is not an attack (the developer can edit any file on disk anyway); this is the official verb that replaces reflection-style hacks — and it stays quiet (pull-based provenance only).
37[override]
"org.example/member -> org.example/wal" = { access = "public" }
"org.example/partner" = { allow-friends = "*" }

38Ключ-ребро называет оба конца ребра стрелкой; ключ-пакет называет один пакет и переписывает его allow-friends. Переопределения применяются вдоль цепочек, которые проходят через объявивший их манифест. То, что ближе к корню, применяется позже и побеждает, так что за корнем всегда последнее слово, а посредник побеждает только на цепочках, в которых участвует.

39 Path-stack semantics. An override applies to chains that pass through its declarant: walking a chain R → … → N → … → P → Q, the effective attributes of the edge P → Q are its declared attributes masked by the [override] tables of the chain's nodes in order, nearer-to-root applied later and winning — the root can re-override any intermediary, the payer always has the final word; between intermediaries, the outer (closer to R) wins on the chains it participates in. Effective attributes are therefore per-chain; E(R) and the grow rule quantify existentially over chains (a package is present / a hop extends the closure if some chain admits it), which is the diamond behaviour exclude already has. Determinism is preserved — masks are static declarations, the graph is acyclic, and the implementation dedups identical mask-states while walking the DAG (override tables are rare, so the practical state count stays small).

40Тот же ключ, override, обслуживает и старую форму-массив [[override]], которая закрепляет замену источника для одной координаты. Две формы различаются по виду, каждая по отдельности законна, а манифест с обеими сразу — громкая ошибка, а не слияние.

41 Syntax note (W1 landing): the manifest already carried [[override]] — the array-of-tables registry-pin form (OverrideSection). The visibility table lives under the same override key as an ordinary table; the wire layer distinguishes the two shapes structurally (array vs table), either form alone is lawful, and one manifest carrying both is a loud validation/serialisation error rather than a silent merge. A future wave may retire or rename the legacy form; until then the coexistence is deliberate.

Что приходит в ваше дерево

42Пакеты, которые метки допускают от вашего корня, образуют действующее множество, и это единственное множество, с которым работает vibe. Разрешение версий идёт только по нему: приватное ребро пакета, который не ваш корень, не вносит ограничения, ничего не скачивает и не может конфликтовать. Лок-файл записывает действующее множество, так что ваш лок никогда не несёт чужих инструментов.

43 Version resolution operates on E(R) only: private edges of non-root packages contribute no constraints, fetch nothing, and cannot conflict. vibe.lock records E(R) — the lock of a consumer no longer contains other packages' dev-world entries. Version unification (one node per (group, name), PROP-003/017) is unchanged within the effective set. A welcome simplification vs code ecosystems: the Cargo-RFC-1977 problem («may private deps duplicate at different versions?») does not arise — an invisible package has no copies at all.

44Дерево зависимостей под vibedeps/ держит ровно это множество. Исключённый или невидимый пакет не оставляет ни папки, ни записи в кэше для вашего мира, ни текста в стартовой полосе.

45 vibedeps/ holds exactly E(R): an excluded or invisible package leaves no slot, no cache entry for the root's world, no lane text. This is the structural fix for the WAL specimen: a wal flow declared private (or friends-only) by whatever requires it simply never arrives in a consumer's tree — no snippet, no vibevm/vibespecs/WAL.xml scaffold, no INDEX row.

46По вашим собственным ребрам идут всегда, включая приватные. Так один [requires] служит и вашим набором для разработки, и вашим контрактом, разделённым по ребрам, а не по секциям: в вашем чекауте приватные инструменты материализуются; когда вас потребляют как зависимость, материализуются только просачивающиеся ребра.

47 Rule (1) of §2.5 — the root's own edges always traverse — combined with explicit private marks resolves the open tail of the equipotence wave (PROP-024): a package's [requires] is simultaneously its dev-set and its contract, split per-edge by access rather than by section. When the package is the consumer root (a dev checkout — [project] or [package], equipotently), all its edges traverse and its private tooling materialises; when it is consumed as a dependency, only its seeping edges do. No separate dev-dependencies section needed.

48Поскольку метка в середине графа может расширить то, что до вас доходит, vibe update печатает изменение действующего множества: какие пакеты входят или выходят и сколько бюджета чтения они добавляют или снимают. Расширение — событие для ревью, а не тихое просачивание.

49 Closure-drift visibility. The lock carries E(R) with each member's lane cost (bytes/tokens of its contribution); vibe update prints the closure diff — packages entering/leaving and the lane-cost delta — so a mid-graph re-export widening (##CLOSURE-DRIFT-CONTROL) is a reviewed event, not a silent seep.

Спросить почему

50vibe why отвечает на вопрос, который система видимости иначе превращает в фольклор. Для присутствующего пакета она печатает цепочку, которая его допускает, каждый переход с его правилом, меткой доступа и источником дружбы. Для отсутствующего — ближайшие перекрытые цепочки и что перекрыло каждую: приватное ребро, отсутствие дружбы, unfriend или exclude. vibe tree несёт те же пометки на каждом узле.

51 Observability: vibe why <group>/<name>. For any package, print the chains that admit it into E(R) — each hop annotated with its rule ((1)/(2)/(3)), access mark, and friendship provenance — and for an absent package, the nearest blocked chains and what blocked them (private edge / missing friendship / unfriend / exclude). The debugging surface without which a visibility system rots into folklore; vibe tree gains the same annotations.

Особые случаи и правила

52Пакет, достижимый двумя путями, присутствует, как только один путь его допускает; exclude на другом пути ничего не меняет. Исключение — вычитание, и объявлять его можно где угодно; расширение — переопределение, и корень всегда может переопределить посредника заново. Дружба, unfriend и печать меняют, какие цепочки открыты, но никогда не меняют, какие версии выбраны: версия пакета, за который поручились, остаётся за поручителем.

For an agent

This page has a machine mirror. The citation carries the version rather than latest, so what an agent quotes does not move under it.

spec://org.vibevm.core/vibevm-docs@1.0.0/model/dependency-visibility

.md.xmlllms.txt