feat!: one-level analysis (clarpse 11.6.0), focus extension pass, not-loaded relationships; remove resolveContextualComponents - #80
Merged
Conversation
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
filteredRelations copied only the outer map, then removed targets from the inner maps it shared with the source. Drawing a diagram filters the diff's relations down to the drawn components, so it removed every relation to an undrawn component from CodeDiff.extractedRels(), and a later render or reader of the same diff saw fewer relations. Each retained source now gets its own copy of its target map. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…d diagram References to repository types the model holds no component for (clarpse's not-loaded state) are kept as NotLoadedRelations on the CodeDiff, with the component they start from, the relation they would be, and whether that component was analysed in full or is a boundary component. They are never drawn. Boundary components become key relations components only when the other end of the changed relation is not a boundary component, are serialised with "boundary": true, and are the first components removed when a diagram is over maxComponentsPerDiagram, context files before the rest. A synthetic module of a boundary file is itself boundary. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…ContextualComponents StriffConfig.setAnalysisDepth(1) with a non-empty filter makes the full pipeline run clarpse's one-level analysis: both revisions are prepared, compiled with the union of their level-one files plus the context files (expandedFiles), and, with a FocusExtender, extended with the files it names and compiled again. The diff is built from the final compile only; every prepared analysis is closed on every path. levelOneBudget and contextBudget cap the two sets separately, and context files never displace level-one files. StriffOperation.analysisScope() reports what was modelled and held back. resolveContextualComponents and its file-name lookup are removed: one-level analysis replaces them. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Zir0-93
marked this pull request as ready for review
September 19, 2026 20:50
Each compile caps level one at levelOneBudget plus the context files it keeps, through clarpse 11.7.0's per-compile budget, so level one never uses the context budget's room. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Integrates clarpse 11.7.0's one-level analysis into striff-lib. With
StriffConfig.setAnalysisDepth(1)and a non-empty filter, the full pipeline models the filter's files in full and the repository files they reference as boundary components, without compiling the rest of the repository. Both revisions load the same referenced files. An optional focus extension pass adds files to analyse in full before the final compile. References to repository types that weren't modelled are kept as not-loaded relationships, not lost.resolveContextualComponentsis removed, so this is 5.0.0.Closes #79
Design
OneLevelAnalysis(package-private) runs per language:prepare()base and head in parallel (ParallelParse, now generic).extra = base.levelOneFiles() ∪ head.levelOneFiles() ∪ context files.compile(extra)on both.FocusExtender:extendFocus(more)on both revisions (a language the filter had no files in is prepared at this point);CodeDiff, the relationships and the diagram are built only from the final compile. EveryPreparedAnalysisis closed infinally, andParallelParsecloses a prepared analysis whose sibling failed. Clarpse holds no daemon between calls, so two prepared analyses per language don't deadlock onNodeDaemonGate: the TypeScript/Python tests run base and head in parallel.StriffOperation.analysisScope()reports, for the whole operation:Decisions implemented
resolveContextualComponentsremoved, along withresolveMissingContextualComponentsand its lookup by bare file name. Version 5.0.0, with "Migrating from 4.x" in the README.NotLoadedRelations (source base component or synthetic module, target name, association, origin) onCodeDiff.notLoadedRelations(). They are never in theRelationsMap, so never drawn. Origin isFOCUSwhen the referencing component was analysed in full (e.g. its target's file was held back by the budget) andBOUNDARYfor a boundary component's reference past level one. After an extend pass, a promoted file's references become internal (tested).maxComponentsPerDiagram, boundary components are removed first (context files before the rest, in unique-name order), and changed components are never removed. Nothing changes for an ordinary analysis, which has no boundary components.CodeDiffexists.expandedFiles. In depth-1 mode they join the extra level-one set of both revisions, so they are modelled as boundary without their own level one. Javadoc updated.contextBudget(default 200) alongsidelevelOneBudget(default 1000), both per language. When the context files exceed the budget, the ones that name the filter's files most often are kept, ties broken by path, and the rest are reported inanalysisScope().contextHeldByBudget().Decision 6 is exact. Each compile caps level one at
levelOneBudgetplus the context files it keeps, through clarpse 11.7.0'sPreparedAnalysis.compile(extra, budget). The prepared budget stays the upper bound the Java solver's load cap is sized from. Context files never displace level-one files, and neither budget can use the other's room. Covered byOneLevelAnalysisTest.levelOneBudgetIsExactWhateverTheContextBudget, which fails without it.Also fixed
RelationsMap.filteredRelationscopied only its outer map and then removed targets from inner maps it shared with the source. Rendering a diagram filters the diff's relations down to the drawn components, so it deleted every relation to an undrawn component fromCodeDiff.extractedRels(). A second render, or any later reader of the same diff, therefore saw fewer relations. Found because a one-level test lostlib.B → deep.Concedeep.Cwasn't drawn. Each retained source now gets its own copy of its target map, with a regression test.Tests
OneLevelAnalysisTest(Java, 17 tests):BOUNDARYnot-loaded relation, not drawn;FOCUSnot-loaded relation;"boundary": trueonly when true;OneLevelDaemonLanguageTest(Python, end to end): union, boundary, not-loadedHelper → Base, and an extend pass promoting the helper. Cleanup: noclarpse-src-<pid>-*directory is left after a successful or a failing operation. Mutation-checked: without thefinallyclose, both cleanup tests fail with the leaked directories listed.OrdinaryAnalysisUnchangedTest: a golden file generated from the clarpse-11.6.0-only commit (1162224) and compared here, covering the change set, all relations, diagram components and PlantUML source, for unfiltered, filtered, and filtered +expandedFilesJava/Python changes. Ordinary output is identical. Relations are read by a fresh extraction, since rendering no longer mutatesextractedRels()(see Also fixed).ParallelParseTest: a produced result whose sibling failed is discarded (closed); nothing is discarded on success.StriffOperationIntegrationTest: the formerresolveContextualComponentstests now cover depth 1 (the parent shows as gray context, an external library reference doesn't crash, depth 1 without a filter is ordinary) and the ordinary filtered case.1162224).Measurements
15 files of one directory are changed synthetically (a field typed with another type of the same directory, plus a method) over the whole repository, base and head. Each run is a separate JVM with
-Xmx6g; peak RSS is from/usr/bin/time, which includes the Python daemon. Single run per cell on an otherwise idle 8-core machine.clients/.../producer/internals)db/models)Orleans.Runtime/Catalog)Breaking changes & migration
StriffConfig.setResolveContextualComponents(boolean)andresolveContextualComponents(). UsesetAnalysisDepth(1)and pass every file of both revisions. Context goes insetExpandedFiles.ParallelParse(package-private) is now generic.CodeDiff.extractedRels()is no longer reduced by rendering.notLoadedDependencies(), orCodeDiff.notLoadedRelations().StriffConfig:setAnalysisDepth,setLevelOneBudget,setContextBudget,setFocusExtender,oneLevel(),DEFAULT_CONTEXT_BUDGET;FocusExtender,AnalysisScope,StriffOperation.analysisScope();NotLoadedRelation,CodeDiff.notLoadedRelations(),ExtractedRelationships.notLoadedRelations();DiagramComponent.boundary();StriffDiagramModel.trimBoundaryComponents(...).🤖 Generated with Claude Code