166 lines
10 KiB
Markdown
166 lines
10 KiB
Markdown
# Empty inheritance-chain scaling diagnosis — 2026-09-11
|
||
|
||
Codex-ytr83r /root/integration_audit. Bounded read-only source diagnosis of root's
|
||
already executed ignored R6 probe. No compiler, Cargo, repeated benchmark,
|
||
production edit, Git mutation or native input by this reviewer.
|
||
|
||
**Finding:** there is avoidable repeated work in the current validation path,
|
||
including full-model scans even when every record has zero fields. This is a
|
||
confirmed source scaling limitation, not a newly demonstrated semantic failure
|
||
or a measurement of optimized GUI latency. The observed debug wall times cannot
|
||
attribute how much cost belongs to the algorithm, profile or contended host.
|
||
|
||
Read issue #1 through owner comment 229 and the updated branch AGENTS.md blob
|
||
`4b8465c8993107062ad2974c15a958d449530e92`, including harness maintenance rules.
|
||
Ownership coordination is [comment 230](http://217.177.34.108:3000/sorokin.oleg.edu/ARCADIA-Studio/issues/1#issuecomment-230).
|
||
Codex-956atf retains core numeric/metamodel work; comment 231 subsequently assigns
|
||
their schema-8 core work to an isolated worktree. No inheritance implementation
|
||
lease is claimed here. This focused report supplements the historical evidence
|
||
below rather than replacing it or reopening its completed semantic work.
|
||
|
||
## What was measured
|
||
|
||
Root invoked `target/debug/deps/r6_data-01b62bfdfd2168ff.exe --ignored --exact
|
||
inheritance_chain_validation_scaling_probe --nocapture`. Executable SHA-256:
|
||
`4e79ed783ad4e147f5e1b4cffa5a41d9d383521cd336e99fc74407b067275ea4`.
|
||
Original evidence: `.local/ytr83r-inheritance-probe/probe.log` and `status.json`.
|
||
|
||
| Records | Root-observed validation wall time | Ratio to preceding size |
|
||
| ---: | ---: | ---: |
|
||
| 250 | 6669.691 ms | — |
|
||
| 500 | 19166.328 ms | 2.87 |
|
||
| 1000 | 38062.849 ms | 1.99 |
|
||
|
||
Test harness: one passed, zero failed, 71.21 seconds. Outer runner: exit 0,
|
||
timeout false, 73.562 seconds. The sum of three printed intervals is 63.899
|
||
seconds; the residual includes fixture construction and other harness work,
|
||
which this probe does not time separately. Do not call the entire 71.21 seconds
|
||
validation time or infer its residual cause.
|
||
|
||
`r6_data.rs:1325` constructs a fresh Project with N top-level OA Record types,
|
||
one supertype chain and no fields/relations/diagrams. `make_record` is at line 15.
|
||
Construction, UUID creation and alias generation happen before each timer.
|
||
The timed `valid` helper at line 56 runs full `validation::validate`, filters
|
||
errors and asserts none; it does not assert an empty warning set. No source
|
||
parsing, serialization, file I/O, commands, layout or drawing is timed. Each
|
||
size runs once; UUIDs and thus map/traversal ordering are freshly generated.
|
||
|
||
The debug test ran while desktop dependencies compiled. Root reports an
|
||
unusually slow host (first core compilation 37m12s, approximately 3 GiB free,
|
||
normal-priority rustc). These observations make environmental contribution
|
||
plausible; no CPU-time, allocation, paging or scheduler measurement isolates it.
|
||
The two observed ratios neither prove linearity nor fit a reliable exponent.
|
||
|
||
## Confirmed source cost
|
||
|
||
`validation.rs:182` constructs one validation snapshot but no shared data index.
|
||
Every record reaches `data::validate_element` (`validation.rs:411`), then all
|
||
records reach `validate_record_cycles` (`validation.rs:609`, `data.rs:1147`).
|
||
Let depth d include the record itself, with d = 1..N in this fixture.
|
||
|
||
| Exact work in this fixture | Source | Count per whole validation |
|
||
| --- | --- | ---: |
|
||
| `effective_fields(base)` for shadow checks | `data.rs:688` | N−1 calls |
|
||
| `effective_fields(self)` for empty-record checks | `data.rs:827` | N calls |
|
||
| `effective_fields(self)` for mandatory Value graph | `data.rs:1153` | N calls |
|
||
| All-element filter visits inside those calls | `data.rs:58` | N(3N−1) |
|
||
| Local-child filter visits for derived records | `data.rs:693`, `model.rs:1828` | N(N−1) |
|
||
| Named-field reference scan for empty records | `data.rs:828` | N² |
|
||
| Ancestry-node visits across those calls plus separate cycle checks | `data.rs:42`, `data.rs:678` | 2N² |
|
||
| Whole identity-vector materializations for supertype existence | `validation.rs:329`, `model.rs:1746` | N−1 vectors of N+1 entries |
|
||
|
||
The ancestry count is `2 sum(d−1) + 2 sum(d) = 2N²`. Each ancestry walk allocates
|
||
a visited BTreeSet and a result Vec, performs Project BTreeMap lookups, and each
|
||
effective-fields call builds another ranks BTreeMap. All field vectors are
|
||
empty, so output size and sorting cannot explain this fixture's repeated work.
|
||
The three full-element data scans contribute `5N²−2N` candidate visits before
|
||
the separate identity-vector materializations/searches are counted.
|
||
|
||
`Project::contains` calls `identities()` afresh, then performs a linear search.
|
||
Each of the N−1 supertype references triggers it even though validation already
|
||
has the complete identity BTreeSet from `validation.rs:198`. This is another
|
||
quadratic floor; optimizing effective fields alone cannot remove it.
|
||
|
||
For this bounded-string, field-free fixture, the inspected path has at least
|
||
quadratic work and an O(N² log N) tree-operation upper bound. There is no current
|
||
ancestor × full-model nested scan *within one* `effective_fields` invocation;
|
||
its existing comment means one model scan per call, not per validation snapshot.
|
||
The mandatory-value sink-removal algorithm itself has no edges here; its
|
||
repeated effective-field graph construction is the relevant cost. Value path
|
||
depth/expansion limits are not exercised and do not bound these scans.
|
||
|
||
This predates B4: the `data.rs` Git blob is identical in original integration
|
||
`0b58107` and inspected HEAD `023e3a8f097158ac84ca47a58cfa917c503804b0`:
|
||
`df061a8cfa0d90a4f94679dc888cdc00c11156a3`.
|
||
Historical [R6 verification](release-data-verification.md) line 32 records older
|
||
single-run optimized Windows 21.070/89.088/391.590 ms and Linux
|
||
22.381/111.662/408.129 ms at these sizes. Those older host/source measurements
|
||
are consistent with superlinear growth, but are neither rerun here nor a current
|
||
performance guarantee. The [data contract](release-data-contract.md) line 148
|
||
already calls for shared computation once per validation snapshot; current
|
||
helpers do not fully implement that performance design.
|
||
|
||
## Bounded alternatives for the core owner
|
||
|
||
1. Reuse validation's existing exact identity set for its reference membership
|
||
checks. Preserve the global namespace (including diagram nodes/artifacts/
|
||
traces), duplicate-ID diagnostics and malformed map-key behavior. This is
|
||
smaller than changing public `Project::contains` globally, but only removes
|
||
the identity-materialization contribution.
|
||
2. Build a borrowed data index per immutable validation snapshot: local fields
|
||
by owner, referenced named record IDs, immediate supertypes, and cycle state.
|
||
Compute/share effective field sequences base-first, preserving original
|
||
IDs/owners and UUID order within each owner; derive existence and mandatory
|
||
Value-edge summaries without rescanning all elements. Use iterative cycle
|
||
processing or bounded explicit stacks. Empty chains should require roughly
|
||
linear graph work plus map costs; actual field-rich output remains
|
||
output-sensitive. N types each adding a field inherently yield Θ(N²)
|
||
materialized inherited field entries if all such lists are requested.
|
||
3. Merely memoizing today's complete helper results cuts repeated calls but
|
||
still walks each full ancestry and scans the model once per owner. Indexing
|
||
only local children also leaves ancestry and identity costs. These are
|
||
possible staged constant-factor improvements, not a near-linear claim.
|
||
|
||
Do not use a persistent UUID-only cache across mutable Projects, silently cap
|
||
valid inheritance depth, remove cycle checks, or change incomplete-model
|
||
diagnostics for speed. For invalid graphs, preserve current diagnostic identity,
|
||
severity and ordering: descendants leading into a cycle are distinct from
|
||
cycle members; missing/wrong-family/cross-layer bases still need their existing
|
||
errors. A validated acyclic fast path with the existing invalid-graph fallback
|
||
is one conservative option. Any production change remains with the core owner.
|
||
|
||
## Minimal falsifiers and next measurement
|
||
|
||
- A later instrumented validation of a small empty chain should reproduce the
|
||
listed counts. Disagreement falsifies this accounting before optimization.
|
||
Flat empty records isolate the full-model scans while removing deep ancestry;
|
||
a star and a chain at equal N separate depth-sensitive work. Fixed UUIDs and
|
||
frozen fixtures remove ordering noise. Do not use timing assertions as unit
|
||
tests.
|
||
- Compare the complete ordered Issue output and unchanged Project for valid
|
||
chains, self/two-node cycles plus a tail into a cycle, missing/wrong-family/
|
||
cross-layer bases, inherited name shadowing and same-snapshot repeated calls.
|
||
Revalidate after base edit, remove, reidentify and Undo using a fresh snapshot
|
||
to expose stale caches. A single inherited field checks identity/order; a
|
||
field-rich chain distinguishes unavoidable output from empty-chain overhead.
|
||
Required Value cycles, optional/Reference recursion and inherited Call/Reply
|
||
paths must retain existing semantics if their shared helpers are changed.
|
||
- After compiler work ends, root/core owner should build one optimized probe
|
||
from a frozen commit with recorded Rust version, target, profile, flags and
|
||
binary hash. Run it outside Cargo with no concurrent builds: one warm-up and
|
||
three measured samples per fixed 250/500/1000 fixture, reporting every sample
|
||
and median. Record process CPU time alongside wall time, working set and host
|
||
conditions; use a bounded timeout (for example 60 seconds per case) and stop
|
||
rather than treating timeout as a result. Compare current source before any
|
||
change with the same-machine candidate; do not compare debug on this host
|
||
directly with historical optimized machines.
|
||
- Finally measure the actual optimized native workflow on a representative
|
||
model: open, one inheritance edit/validation, responsive redraw, Save and
|
||
Undo/Redo. Separate core validation from parsing/layout/persistence and count
|
||
validation invocations. Only that gate can establish user-visible latency;
|
||
the current ignored probe alone cannot.
|
||
|
||
No new latency budget or required release threshold is invented here. Root and
|
||
the core owner should choose the next change from controlled optimized evidence
|
||
and the actual authoring workload, preserving B4's independent acceptance gates.
|