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 list — but 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§
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.gitfile (agitdir: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_NAMESbelow andbrink-project-config’sfind_configwalk-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’sRealFswalk 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’sRealFsandbrink-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.brinkis unaffected.
Traits§
- Source
Tree - A source of
.brinkfiles: 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. SeeIGNORED_DIR_NAMES.