Finalize import discovery documentation and audits

This commit is contained in:
2026-10-19 21:23:47 +00:00
parent 898035d83a
commit f6a6b0184b
13 changed files with 172 additions and 11 deletions

80
docs/internal/imports.md Normal file
View File

@@ -0,0 +1,80 @@
# Import Discovery and Scheduling Internals
The [configuration contract](../config.md#explicit-imports) owns selector syntax,
defaults, requiredness, placement, inspection evidence, and observable ordering.
This note records implementation flow and private identities for maintainers.
## Discovery and acquisition
Each source's root directive is parsed into presence-aware declarations and
resolved against load-wide defaults. Candidate selection preserves a normalized
namespace path separately from canonical access identity: overlapping roots
coalesce the same candidate spelling in that namespace, while aliases reached
through distinct spellings retain separate inclusion routes for admission.
Directory searches walk each distinct normalized root once, apply all filename
patterns to discovered names, and form a set union of matching candidates across
overlapping roots. Exclusions are applied as set difference after discovery and
candidate normalization. They do not suppress discovery or resource errors.
Directory traversal tracks canonical directories on the active traversal path.
It adds an identity when descending and removes it when the frame is popped, so
only a back-edge to an active directory is a traversal cycle; a later alias is
not mistaken for one. This is separate from import dependency-cycle detection.
For host sources, discovery uses rooted `Lstat` and canonical containment. Native
sources use `fs.ReadLinkFS` inspection when supplied; otherwise traversal follows
the capabilities and behavior of the provided `fs.FS`, without claiming a
general sandbox guarantee.
Acquisition remains authored: declarations are visited in source order and each
selected candidate set in namespace-path lexical order. This preserves source
records, IDs, source-local version checks, and callback ordering. The acquired
inclusion graph is retained separately from composition scopes so cycles that
cross item boundaries remain detectable. Source discovery does not itself choose
sequence assembly order.
## Stable keys and scheduling
The shared scheduler compares immutable tuples component by component using Go's
bytewise string order; if one tuple is a prefix of another, the shorter tuple
sorts first. The import key is
`(namespace-kind, namespace-anchor, resource-kind, resource-path)`:
- Namespace kind is `host` or `native`. Host resource paths are canonical
absolute paths rendered with slash separators; native paths retain their
namespace-relative identity.
- Anchors come from explicit input positions, not discovery order: main is
`(0,0)` and underlay/input positions are `(group+1,input+1)`, each encoded as
fixed-width decimal. Host accesses in one scheduled tier share its host anchor.
A native filesystem namespace uses its earliest explicit selecting position
in that tier. Filesystem tokens distinguish namespace equality, not sort order,
so separately constructed filesystems with the same label remain distinct.
- Resource kind is `file` or `synthetic`. A synthetic root uses its explicit
input anchor and an empty resource path rather than a display label or token
address.
Inheritance keys are
`("definition", scope-pointer, definition-pointer)`, where both pointers use
canonical escaped semantic path spelling. Source IDs are not part of the key.
Both integrations use the same Kahn scheduler: it deduplicates dependency edges,
keeps currently ready nodes in a min-heap, and selects the smallest ready key
after every completion. Its scheduling cost is `O(E + V log V)` time and
`O(V + E)` additional memory, excluding key construction, tuple copying, and
tuple comparisons. On a stalled graph, deterministic DFS over the residual graph
returns a closed cycle rotated to its smallest key; blocked dependents are not
reported as cycle members.
Import composition schedules a main tier or one underlay group as a single
strict-scope graph. Item contributions own nested local strict-mapping scopes;
their helpers complete before the item is placed in its outer scope. Inheritance
uses the same ready-node rule inside each sibling mapping scope, while preserving
the authored mapping order in its output. These scopes do not flatten into one
global graph, and independent precedence tiers remain separate.
The main owners are [`import_selection.go`](../../internal/engine/import_selection.go),
[`directory_walk.go`](../../internal/engine/directory_walk.go),
[`import_graph.go`](../../internal/engine/import_graph.go),
[`dependency_order.go`](../../internal/engine/dependency_order.go), and
[`inheritance_schedule.go`](../../internal/engine/inheritance_schedule.go).
Their focused behavior is covered by import-selection, scheduler, and scheduling
integration tests under `internal/engine`.