Skip to content

fix(scoring): keep generic type names proportional to the model - #241

Merged
blackopsrepl merged 2 commits into
mainfrom
fix/compact-generic-type-names
Nov 10, 2026
Merged

blackopsrepl merged 2 commits into
mainfrom
fix/compact-generic-type-names

Conversation

@blackopsrepl

Copy link
Copy Markdown
Collaborator

Closes #238. Two commits: stream closures built in narrowly generic functions (public stream signatures unchanged), then the replica constraint builder moves out of the descriptor type (BREAKING for solverforge-scoring's director API; no downstream user).

uc-furnace test build (line-tables debug info): .debug_str 2.82 GB -> 0.37 GB, longest name 8.0 MB -> 1.0 MB; with full debug info the test binary links (.debug_str 1.31 GB, was 3.68 GB and failing) and passes 78+3 tests.

Evidence on bc60fe5 (clean tree): make ci-local + make lint EXIT 0, 1725 passed / 0 failed over 116 result lines; public API check EXIT 0 (scoring snapshot updated); zero-regression gate vs v0.25.1 (default trials, isolated CPU, 5 layouts) passed all 13 cases with semantic match.

A closure written inside a generic method has a type that names every
generic parameter of that method. The stream combinators built the closures
they store inline, so each one repeated the whole upstream stream type:
`filter` wrapped the predicate in a closure typed by the previous filter
chain, doubling the type at every chained filter, and `penalize`/`named`
repeated the extractor and filter again in the weight and filter closures.
Debug info prints these types in full; a 30-constraint app (uc-furnace)
produced 2.82 GB of debug strings with single names of 8 MB.

Each such closure is now built in a function generic only over what it
captures (stream/closures.rs, projected_stream/row_closures.rs and narrow*
functions inside the n-ary stream macros). Public stream signatures are
unchanged. On uc-furnace the line-tables debug strings drop to 0.71 GB and
the constraint-set type from 266 KB to 66 KB of text.
…scriptor type

ReplicaDescriptor<'d, S, C> carried the constraint-set constructor
fn(&S) -> C, so every replica-capable director spelled the constraint set
twice in its type: ScoreDirector<S, C, ReplicaDescriptor<'_, S, C>>. The
constructor is now a field of the director, set by the new
ScoreDirector::with_replicas / with_replicas_weighted /
with_replicas_in_mode constructors, and the director borrows the descriptor
as a plain &SolutionDescriptor. DirectorDescriptor loses its type parameters
and its replica() method becomes share(). Forking and reset-rebuild behave
as before.

On uc-furnace the director type halves to the constraint set's 66 KB, the
line-tables debug strings drop from 0.71 GB to 0.37 GB (2.82 GB before
these fixes), the longest name from 2.0 MB to 1.0 MB (8.0 MB before), and
the test binary with full debug info links and passes.

BREAKING CHANGE: solverforge-scoring removes ReplicaDescriptor. Build a
replica-forking director with ScoreDirector::with_replicas(solution,
constraints, constraint_builder, &descriptor, entity_counter) (or the
_weighted/_in_mode variants) instead of with_descriptor(solution,
constraints, ReplicaDescriptor::new(&descriptor, constraint_builder),
entity_counter). DirectorDescriptor has no type parameters, and
DirectorDescriptor::replica() is replaced by share().

Closes #238
@blackopsrepl
blackopsrepl merged commit bc60fe5 into main Nov 10, 2026
7 checks passed
@blackopsrepl
blackopsrepl deleted the fix/compact-generic-type-names branch November 10, 2026 10:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix: core generic types make debug type names grow to megabytes

1 participant