Skip to content

Feat/prune unreferenced models#50

Merged
fredbi merged 3 commits into
go-openapi:masterfrom
fredbi:feat/prune-unreferenced-models
Jun 22, 2026
Merged

Feat/prune unreferenced models#50
fredbi merged 3 commits into
go-openapi:masterfrom
fredbi:feat/prune-unreferenced-models

Conversation

@fredbi

@fredbi fredbi commented Jun 22, 2026

Copy link
Copy Markdown
Member

Change type

Please select: 🆕 New feature or enhancement|🔧 Bug fix'|📃 Documentation update

Short description

Fixes

Full description

Checklist

  • I have signed all my commits with my name and email (see DCO. This does not require a PGP-signed commit
  • I have rebased and squashed my work, so only one commit remains
  • I have added tests to cover my changes.
  • I have properly enriched go doc comments in code.
  • I have properly documented any breaking change.

fredbi and others added 3 commits June 22, 2026 16:08
Definition provenance was emitted inline during the schema build under the
type's short leaf name, but reduceDefinitionNames renames collision groups
afterwards (cross-package same-named models: Item -> XItem/YItem) without
touching provenance. Every /definitions/<leaf>... pointer for a renamed
definition was left dangling, so the OnProvenance consumer (the genspec TUI)
could not resolve it to a spec node. This affected any scan with a
cross-package name collision, independent of model pruning.

OnProvenance is a push stream (RecordOrigin fires immediately and accumulates
nothing), so inline anchors cannot be retracted after the rename. Buffer
definition-scoped anchors instead: BeginDefOrigins/EndDefOrigins open a window
around each definition build keyed by its fully-qualified DefKey; RecordOrigin
buffers inside the window and fires inline outside it (path, response, info and
parameter anchors are never renamed by reduction). reduceDefinitionNames now
returns its old->new rename map, and FlushDefOrigins re-points each buffered
anchor to the definition's final name and emits it once names are settled.

Witness: name-identity-mixed and name-identity-3way join the geometry test,
plus a focused TestCoverage_ProvenanceCollisionRename. Before the fix the mixed
fixture emits 8 dangling anchors; after, every emitted anchor resolves against
the rendered spec.

Zero golden drift: provenance is a side channel and never alters the spec.

Signed-off-by: Frederic BIDON <fredbi@yahoo.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
ScanModels (`-m`) deliberately emits every swagger:model type, reachable or not.
On a large shared library that buries the wanted models under noise; users worked
around it with go-swagger's `flatten`, partly to dodge cross-package name
collisions that an unused model should never have caused (go-swagger/go-swagger#2639).

Add Options.PruneUnusedModels: with ScanModels, run discovery as before, then drop
every discovered definition not transitively referenced from a reachability root.
Roots are the paths (operation body parameters + response schemas), the shared
responses and parameters, and every definition supplied via InputSpec — overlay
definitions are pinned (never pruned, seeded as roots). A model referenced only by
another unreferenced model is pruned too; recursive/cyclic models terminate on a
visited set. Without ScanModels the flag is a no-op (the set is already
reachable-only) and says so with one Hint.

The prune runs BEFORE reduceDefinitionNames, in the fully-qualified definition-key
namespace. That ordering is the point of the feature, not a detail: name reduction
deconflicts colliding leaves (a.Thing / b.Thing -> AThing / BThing). Pruning the
unused twin first means the collision never materialises, so the surviving model
keeps its bare leaf name with no concat churn. Each prune raises a located
scan.pruned-unused Hint; the collision renames the reduce stage still performs are
surfaced as located scan.renamed-definition Hints. Buffered provenance for a pruned
node is dropped, so no anchor dangles.

Fixture enhancements/prune-unused exercises the reachable closure (root -> chain ->
recursive node), the dead chain, and the collision pair; tests lock both regression
witnesses (collision evaporation to a bare name; InputSpec pinning) plus the no-op,
diagnostics and no-orphan-provenance contracts. Default false: flag-off output is
byte-identical.

Signed-off-by: Frederic BIDON <fredbi@yahoo.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Document Options.PruneUnusedModels as a new shaping-the-output page (weight 16,
between type-discovery and resolving-name-conflicts). Prose-only: presents the
option, what it is useful for (scanning a shared model library with -m and
keeping only the reachable subset), and contrasts the three emission modes —
reachable-only (default), every model (ScanModels), and models-then-pruned
(ScanModels + PruneUnusedModels).

Covers what counts as reachable (path/response/parameter roots, InputSpec defs
pinned), the before-name-reduction ordering that makes pruning avoid spurious
cross-package collision renames, and the scan.pruned-unused / scan.renamed-
definition diagnostics. Cross-links the type-discovery page (forward, from its
"Standalone" note) and the resolving-name-conflicts "What's next".

Markdown-lint and link-check clean.

Signed-off-by: Frederic BIDON <fredbi@yahoo.com>
Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@codecov

codecov Bot commented Jun 22, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 74.23313% with 42 lines in your changes missing coverage. Please review.
✅ Project coverage is 81.85%. Comparing base (b1ce919) to head (cc31875).
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
internal/builders/spec/prune.go 64.58% 19 Missing and 15 partials ⚠️
internal/scanner/scan_context.go 88.23% 2 Missing and 2 partials ⚠️
internal/builders/spec/reduce.go 85.71% 2 Missing and 1 partial ⚠️
internal/builders/spec/spec.go 91.66% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master      #50      +/-   ##
==========================================
- Coverage   81.98%   81.85%   -0.14%     
==========================================
  Files          79       80       +1     
  Lines        7440     7594     +154     
==========================================
+ Hits         6100     6216     +116     
- Misses        994     1015      +21     
- Partials      346      363      +17     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

@fredbi fredbi merged commit 3f0612e into go-openapi:master Jun 22, 2026
21 of 23 checks passed
@fredbi fredbi deleted the feat/prune-unreferenced-models branch June 22, 2026 17:33
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.

1 participant