Skip to main content

Crate brink_source_tree

Crate brink_source_tree 

Source
Expand description

The SourceTree seam (decision-log “Native source-loading seam: a SourceTree trait with a map-backed impl; the root is caller-supplied”, 2026-07-22; issue #1278): a host-agnostic way to enumerate and read native .brink source files.

Extracted from brink-db into this L0 leaf crate (decision-log 2026-07-23, issue #1323 ruling on #1325) so both brink-db (native discovery) and brink-project-config (config discovery, #1312) can depend on it without a project-config -> brink-db -> brink-analyzer -> project-config cycle. brink-db re-exports SourceTree so brink_db::SourceTree still resolves for existing consumers.

InMemory is brink-web’s discovery seam directly; the host-only implementations (RealFs, GitRev) live in brink-driver and back brink_driver::discover_native (issue #1288) — a normal native compile and the brink ide git-baseline diff path, respectively.

§The contract

SourceTree::list enumerates every source key, sorted deterministically by key — never in filesystem/OS iteration order, which is unspecified and can vary between runs. Keys are root-relative (forward-slash-joined, matching how .brink module paths are derived downstream). SourceTree::read reads the source text for a key previously returned by listbut callers may also probe candidate keys list never returned (e.g. find_config_in_tree’s #1370 ancestor-probing walk, which never calls list at all). A SourceTree::read implementation MUST surface a nonexistent key as io::ErrorKind::NotFound, not some other error kind — callers that probe speculatively treat NotFound as “no candidate here, keep going” and treat every other error kind as fatal.

§Policy asymmetry: list may be key-kind-scoped, read never is

list’s enumeration scope is entirely implementation-defined — nothing in this trait requires it to return only native .brink keys. brink-driver’s RealFs, for instance, scopes list to .brink only (the native discovery / brink ide shape; issue #1404 deleted a second, wider .brink + .ink scope once tracing showed every caller of that wider scope either filtered list()’s output back down to .brink itself or never called list() at all, so the extra .ink keys were never actually observable). read, however, has no equivalent key-kind scoping on any implementation — whether a key is native (.brink) or not plays no role in whether read will serve it, regardless of what that same implementation’s list would ever enumerate. A RealFs-scoped tree’s read("brink.toml") still succeeds if that file is on disk, even though its list() would never return that key.

This is a claim about key-kind scoping specifically, not a claim that every implementation serves every key that physically exists: a SourceTree may still layer a per-key overlay unrelated to nativeness. brink-cli’s EditOverlay, for instance, reports NotFound for a key it has marked removed even though that file is still on disk — a moved/deleted-key overlay, not list-parity scoping keyed on whether the file is native. That axis is orthogonal to this section and remains legal.

This asymmetry is intentional, not an oversight: it is exactly what lets find_config_in_tree probe for a manifestly non-native brink.toml key against any SourceTree — including one scoped to .brink alone — without needing a widened list or a second seam. The seam itself does not police “nativeness” on read; a consumer that needs that guarantee enforces it itself. brink-driver’s discover_native is the sharp edge of this: it inspects every key list returns and rejects the whole discovery (DiscoverError::NonNativeKey) if any of them is not .brink — but that check runs against list’s output only, is specific to that one consumer, and says nothing about what read will or won’t serve. Do not assume a SourceTree implementation refuses to read non-native keys just because its list is native-scoped.

The root itself is never discovered inside the seam (no implementation walks upward looking for a project marker) — it is always supplied by the caller, which resolves it however is appropriate for that host (a brink.toml walk-up for the CLI, a pushed project root for web/LSP). It is held by the implementation at construction (the #1323 layering ruling), not passed per call: list takes no root parameter, matching read, which never had one. Issue #1371 removed list‘s root parameter for exactly this reason — before the fix, RealFs silently ignored a root argument to list while GitRev silently used it instead of its own constructor-held root, so the same call could resolve two different trees’ worth of keys depending on which impl happened to be behind the dyn SourceTree. Dropping the parameter makes “root is constructor-held” the only contract there is to honor.

Re-exports§

pub use walk::Walk;
pub use walk::WalkEntry;

Modules§

walk
The shared recursive directory walk (issue #1433).

Structs§

InMemory
Map-backed SourceTree: the test and web seam.

Constants§

GIT_DIR_NAME
The directory-entry name that marks a git repository root — either an ordinary clone’s .git/ directory, or a linked worktree’s .git file (a gitdir: pointer, e.g. how this repository’s own .claude/worktrees/* are laid out). A single source of truth for that name (issue #1435): before this constant existed, IGNORED_DIR_NAMES below and brink-project-config’s find_config walk-up bound each hardcoded their own ".git" literal, free to drift apart.
IGNORED_DIR_NAMES
Directory names a recursive filesystem walk should never descend into — build output and VCS/dependency metadata that is never a valid source location and can be enormous. Originally added to brink-driver’s RealFs walk alone (issue #1381: #1370 fixed config discovery to probe ancestors directly instead of enumerating, but the native compile walk — the other call path paying the same cost — still descended into these). Promoted here (issue #1402) so every host-side recursive walk — brink-driver’s RealFs and brink-lsp’s workspace scan alike — prunes the same directories instead of each re-deriving its own list. Matched by exact directory-entry name, not path suffix, so a source file legitimately named e.g. target.brink is unaffected.

Traits§

SourceTree
A source of .brink files: enumerate what exists under a root (held by the implementation since construction — see the module docs), and read any key, whether or not enumeration returned it.

Functions§

is_ignored_dir
Whether name (a single directory-entry file name, not a path) is a conventionally-ignored directory a recursive walk must not descend into. See IGNORED_DIR_NAMES.