Record import bookkeeping scalability findings
This commit is contained in:
@@ -75,3 +75,97 @@ overlay, and passive-resource-context tests. Add a focused behavioral regression
|
|||||||
only for a consequential gap exposed by the change; do not assert incidental
|
only for a consequential gap exposed by the change; do not assert incidental
|
||||||
canonicalization/stat call counts. Run the development check and applicable
|
canonicalization/stat call counts. Run the development check and applicable
|
||||||
ownership race checks after remediation.
|
ownership race checks after remediation.
|
||||||
|
|
||||||
|
## Algorithmic Audit Scope
|
||||||
|
|
||||||
|
Audited worktree: `d898cb1`, with production code at the reviewed implementation
|
||||||
|
revision above. This follow-up used source inspection and graph caller traces,
|
||||||
|
not benchmarks or new runtime measurements. It covered acquisition and import
|
||||||
|
bookkeeping, scope scheduling and projection, filesystem context handoffs,
|
||||||
|
inheritance preparation/combination/finalization, and reflective projection and
|
||||||
|
schema construction.
|
||||||
|
|
||||||
|
Findings 2–3 are retained inefficiencies in paths carried through the refactor,
|
||||||
|
not algorithmic regressions introduced by the consolidation. They warrant
|
||||||
|
focused follow-up without changing the selected configuration model. The audit
|
||||||
|
did not identify an additional correctness defect. Finding 1 remains open.
|
||||||
|
|
||||||
|
The selected stable Kahn scheduler, deterministic sorting, composition rules,
|
||||||
|
scope boundaries, and required ownership copies are not reconsidered here.
|
||||||
|
Previously deferred experiments in [future.md](future.md#3-performance-experiments)
|
||||||
|
and the [clone review](future.md#4-clone-traversal-review) retain their separate
|
||||||
|
disposition. These findings do not establish new public complexity guarantees,
|
||||||
|
input restrictions, performance thresholds, or release gates.
|
||||||
|
|
||||||
|
## 2. Avoid Searching All Sources For Each Empty Import Selection
|
||||||
|
|
||||||
|
Status: open. Priority: low. Category: algorithmic efficiency.
|
||||||
|
|
||||||
|
**Evidence.** `walkDeclarations` calls `recordEmptyImportSelection` for each
|
||||||
|
optional declaration that admits no source. In
|
||||||
|
[import_acquisition.go](../../internal/engine/import_acquisition.go), lines
|
||||||
|
289–300, the latter finds the declaring source by scanning `s.sources` from the
|
||||||
|
beginning, even though traversal already knows which source owns the declaration.
|
||||||
|
|
||||||
|
**Complexity.** With S acquired sources and D empty declarations, source lookup
|
||||||
|
takes O(S × D) comparisons in the worst case, excluding path-copying and source
|
||||||
|
selection itself. A broad main import of N constant-size fragments, each with
|
||||||
|
one empty optional declaration, visits source positions 1 through N: the sum of
|
||||||
|
lookup work is Θ(N²), despite linear source and selection-evidence volume and
|
||||||
|
constant import depth. Existing input budgets bound the workload but do not
|
||||||
|
remove this avoidable scaling within those budgets.
|
||||||
|
|
||||||
|
**Potential refactoring.** Carry the declaring source's integer index through
|
||||||
|
the declaration traversal, or maintain a traversal-local source-ID-to-index map.
|
||||||
|
Either approach makes each evidence-owner lookup O(1), with O(S + D) total
|
||||||
|
bookkeeping for the map alternative. Keep source order and IDs unchanged. Use
|
||||||
|
indices rather than retained pointers into the appendable source slice, and
|
||||||
|
preserve optional-missing rollback and failed-source retention if maintaining
|
||||||
|
an index across admission.
|
||||||
|
|
||||||
|
**Verification.** Reuse the source-local/detached empty-selection and partial
|
||||||
|
failure coverage in [import_evidence_test.go](../../internal/engine/import_evidence_test.go).
|
||||||
|
A broad-fragment behavioral case is useful if existing coverage does not protect
|
||||||
|
the chosen index handoff. Verify the removed scan by source review rather than
|
||||||
|
adding timing thresholds or assertions about private lookup counts.
|
||||||
|
|
||||||
|
## 3. Restrict Import-Scope Edge Preparation To Relevant Nodes
|
||||||
|
|
||||||
|
Status: open. Priority: medium. Category: algorithmic efficiency and allocation
|
||||||
|
scaling.
|
||||||
|
|
||||||
|
**Evidence.** `scheduleAcquisitionScopes` in
|
||||||
|
[imports.go](../../internal/engine/imports.go), lines 57–64, recursively schedules
|
||||||
|
the outer scope and every pending item-local scope using the same complete
|
||||||
|
inclusion graph. `scheduleContributionSlots` in
|
||||||
|
[import_graph.go](../../internal/engine/import_graph.go), lines 185–213, constructs
|
||||||
|
a local identity-to-slot map but then scans every graph edge and allocates an
|
||||||
|
edge slice with capacity `len(graph.edges)` for each scope with at least two
|
||||||
|
eligible contributions. Most edges need not touch that scope.
|
||||||
|
|
||||||
|
**Complexity.** For Q such scopes and E inclusion edges, preparing the scheduler
|
||||||
|
inputs takes O(Q × E) edge inspections and requests O(Q × E) edge-slice capacity
|
||||||
|
over the operation. This is cumulative allocation demand, not a claim that all
|
||||||
|
those slices remain live together. For N sibling item imports, each with one
|
||||||
|
distinct mapping helper, Q and E are both Θ(N), making this preparation Θ(N²)
|
||||||
|
even at constant nesting depth. The selected scheduler itself is not the
|
||||||
|
problem: each small item-local graph has constant size, and the outer graph
|
||||||
|
requires its normal deterministic scheduling work.
|
||||||
|
|
||||||
|
**Potential refactoring.** Build a traversal-local adjacency index once after
|
||||||
|
acquisition, then gather edges for a scope by its participating source identities
|
||||||
|
and retain only edges whose endpoints both have local slots. Alternatively,
|
||||||
|
partition the existing edges by their applicable scopes once. Preserve the
|
||||||
|
current endpoint-membership rule, item-boundary representation, slot placement,
|
||||||
|
group scheduling, and stable Kahn tie-breaking. For the broad sibling family,
|
||||||
|
this reduces edge preparation to O(E + P), where P is the total number of local
|
||||||
|
slots, followed by the unchanged scheduler cost. Keep this an indexing change
|
||||||
|
around the agreed scheduler, not a different ordering algorithm or a cross-load
|
||||||
|
cache.
|
||||||
|
|
||||||
|
**Verification.** Reuse item/helper interleaving and grouped import scheduling
|
||||||
|
coverage in [imports_test.go](../../internal/engine/imports_test.go) and
|
||||||
|
[load_request_test.go](../../internal/engine/load_request_test.go), together with
|
||||||
|
existing destination/provenance evidence tests. Cover broad independent item
|
||||||
|
scopes if a consequential gap remains; verify index construction and edge
|
||||||
|
visitation bounds by source review without new performance gates.
|
||||||
|
|||||||
Reference in New Issue
Block a user