chore(config): retire legacy ProjectConfigLoader static API (#52)#52
Merged
Conversation
…s.include, indexing.parsers Prep for Phase-2 retirement of the legacy ProjectConfigLoader static API. The Analyzer pipeline currently reads language/detector/parser/parallelism filters from the legacy ProjectConfig POJO via ProjectConfigLoader.loadProjectConfig; moving those call sites onto the injected CodeIqUnifiedConfig bean requires the unified tree to carry the same fields. This commit adds: - DetectorsConfig: categories, include (List<String>). empty() updated. - IndexingConfig: parsers (List<String>); parallelism changed from String to Integer with null = auto-detect. empty() updated. - UnifiedConfigLoader: reads detectors.categories/include (snake_case) with camelCase aliases detectorCategories/detectorInclude (deprecated, per-load WARN via existing pick() helper); reads indexing.parsers; parses parallelism as Integer via requireIntOrNull. - EnvVarOverlay: CODEIQ_DETECTORS_CATEGORIES, CODEIQ_DETECTORS_INCLUDE, CODEIQ_INDEXING_PARSERS (CSV); CODEIQ_INDEXING_PARALLELISM now parses to Integer and throws ConfigLoadException on malformed input. - ConfigMerger: merges the three new leaves with full provenance tracking. - ConfigValidator: indexing.parallelism must be > 0 if set (null = auto). - ConfigDefaults.builtIn(): parallelism = null (auto), parsers = [], detectors.categories = [], detectors.include = []. No behavior change on the default path. - ProjectConfigLoader.translateLegacyToUnified: maps the nested legacy shape (detectors.categories, detectors.include, parsers map, pipeline.parallelism) plus the flat top-level aliases detector_categories / detector_include into the new unified fields. parsers map is flattened to its values (Analyzer never consumed the per-language map at runtime). - docs/codeiq.yml.example: documents parsers, detectors.categories, and detectors.include; notes parallelism: null = auto. Test coverage (+16 cases): - UnifiedConfigLoaderTest: snake_case load, camelCase alias WARN, parallelism as Integer, malformed parallelism throws, missing detectors section = empty lists. - EnvVarOverlayTest: CSV parsing for the three new vars, Integer parallelism, malformed parallelism throws. - ConfigMergerTest: layer-replacement for categories/include/parsers, parallelism merge, provenance attribution. - ConfigValidatorTest: parallelism > 0 rejection + null-is-valid (auto). - ConfigDefaultsTest: baseline assertions for new defaults. Full suite: 3275 -> 3291 tests, 0 failures, 31 skipped. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…m CodeIqUnifiedConfig Before: runWithCache/runBatchedWithCache/runAnalyzeBatched each called ProjectConfigLoader.loadProjectConfig(root) and re-parsed .osscodeiq.yml from disk to pull detector category/include filters, language filter, exclude patterns, and pipeline.parallelism. The unified config bean has already resolved these at startup (UnifiedConfigBeans.codeIqUnifiedConfig) so the per-call file I/O is pure waste. After: inject CodeIqUnifiedConfig into Analyzer and project the relevant leaves through a small private PipelineFilters record (categories, include, languages, exclude, parallelism). All three call sites now read filters from the injected tree; no file I/O, no legacy POJO, no static loader. Back-compat constructor (6-arg, used by 5 existing tests) preserved — defaults the unified overlay to CodeIqUnifiedConfig.empty(), matching the pre-Phase-B "no .osscodeiq.yml present" path (no filters, auto parallelism). SmartIndexTest.setUp updated to the new 9-arg primary constructor with CodeIqUnifiedConfig.empty() (no filter semantics — the test doesn't exercise filters). Full suite: 3291 tests, 0 failures, 31 skipped. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
CliOutput.configureFromOptions called ProjectConfigLoader.loadIfPresent to re-apply cache_dir / max_depth / max_radius from .osscodeiq.yml onto the injected CodeIqConfig bean. Those fields are already resolved at Spring startup by UnifiedConfigBeans.codeIqConfig (via ConfigResolver + UnifiedConfigAdapter), so the re-read was pure duplication. Removed the reload call. The `root` parameter became unused and was dropped from the method signature; two callers (AnalyzeCommand, IndexCommand) updated accordingly. Full suite: 3291 tests, 0 failures, 31 skipped. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
… config pipeline The legacy static API (ProjectConfigLoader.loadIfPresent / loadProjectConfig / parseProjectConfig) is being removed in the next commit. This test file previously exercised those methods directly; all cases are rewritten to drive the same behaviour through the Phase-B canonical shim ProjectConfigLoader.loadFrom(Path), asserting on the returned CodeIqUnifiedConfig (and the projected CodeIqConfig via UnifiedConfigAdapter for legacy-POJO-shaped assertions). Ported cases (11): - legacy cache_dir/max_depth/max_radius flow through to CodeIqConfig. - legacy languages/detectors.categories/detectors.include/exclude/parsers/ pipeline sections populate CodeIqUnifiedConfig. - missing .osscodeiq.yml returns CodeIqUnifiedConfig.empty() with no deprecation warning emitted. - SafeConstructor rejects unsafe YAML tags without executing arbitrary code (either returns a safe representation or throws ConfigLoadException; no code execution is the invariant). Dropped cases (3): - nestedAnalysisSectionDoesNotCrash / nestedOutputSectionDoesNotCrash: exercised dead branches inside the legacy applyOverrides that are being deleted entirely. - invalidMaxDepthFallsBackToDefault: the legacy applyOverrides silently coerced non-numeric max_depth back to the default via its toInt helper. The unified loader is deliberately strict — malformed scalars throw ConfigLoadException with the field path. That behaviour change is already covered by UnifiedConfigLoaderTest; preserving the old lenient semantics would mask real misconfiguration. Full suite: 3291 -> 3288 tests (-3 net), 0 failures, 31 skipped. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…d-pipeline tests) ConfigDrivenPipelineTest exclusively exercised ProjectConfigLoader.parseProjectConfig(Map) and .loadProjectConfig(Path) — the deprecated static legacy-POJO parsers being deleted in the next commit. Every unique assertion has equivalent coverage on the unified pipeline: - languages/detectors.categories/detectors.include/exclude/parsers/pipeline map parsing: covered by UnifiedConfigLoaderTest (loadsDetectorsCategoriesAndInclude, loadsIndexingParsersList, loadsIndexingParallelismAsInteger, fullFileRoundTripsEveryField). - legacy .osscodeiq.yml end-to-end with flat keys: covered by ProjectConfigLoaderApplyOverridesTest (ported in the prior commit). - empty/missing-file semantics: covered by UnifiedConfigLoaderTest.missingFileProducesEmptyOverlay and ProjectConfigLoaderApplyOverridesTest.missingConfigFileReturnsEmptyOverlay. - ProjectConfig.empty() "no filters" assertion: equivalent to CodeIqUnifiedConfig.empty() behavior pinned in ConfigDefaultsTest. No unique coverage lost. Removing the file (not porting) keeps the test tree clean — parseProjectConfig is a private implementation detail of the legacy shim, not an API worth separate test coverage after migration. Full suite: 3288 -> 3277 tests (-11), 0 failures, 31 skipped. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…aned ProjectConfig POJO With Analyzer and CliOutput migrated off the legacy static API (prior two commits) and the legacy-only tests rewritten against loadFrom(Path) (prior two commits), the deprecated surface has no remaining callers. Removed from ProjectConfigLoader: - public static boolean loadIfPresent(Path, CodeIqConfig) - public static ProjectConfig loadProjectConfig(Path) - package-private static ProjectConfig parseProjectConfig(Map) - private static applyOverrides / toInt helpers (only used by loadIfPresent) - LEGACY_CONFIG_FILE_NAMES array (only used by the deleted statics; the new surface only honors codeiq.yml and .osscodeiq.yml). Inlined parseProjectConfig's logic directly into translateLegacyToUnified so the legacy ProjectConfig POJO has no remaining reference. The translator now reads languages/detectors/exclude/parsers/pipeline.* in place from the raw YAML map, without the intermediate POJO. Deleted: - src/main/java/io/github/randomcodespace/iq/config/ProjectConfig.java (orphaned after inlining) Kept: - ProjectConfigLoader#loadFrom(Path) — canonical Phase-B surface. - ProjectConfigLoader.LoadResult — returned record. - translateLegacyToUnified + readAndTranslateLegacy + countLegacyKeys — internal helpers for the .osscodeiq.yml deprecation shim. ProjectConfigLoaderTest trimmed: removed 5 tests that exclusively exercised the deleted legacy-file-name (.code-iq.yml/.yaml) paths plus the removed return-false-and-mutate-CodeIqConfig semantics. Ported 2 meaningful tests (empty-file handling, invalid-YAML resilience) onto loadFrom(Path); those pin safety behaviour of the deprecation shim. Full suite: 3277 -> 3272 tests (-5), 0 failures, 31 skipped. Co-Authored-By: Claude Opus 4.7 (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
Post-Phase-B cleanup. Eliminates the last setter-mutation path on
CodeIqConfigby retiring the deprecated static API onProjectConfigLoaderand migrating all runtime callers to read directly from the injectedCodeIqUnifiedConfigbean. Closes follow-up task #52.Phase 1 — schema gap fix
The investigation revealed the unified tree was missing three fields that
.osscodeiq.ymllegitimately exposed:detectors.categories,detectors.include,indexing.parsers. Without these, retiring the legacy statics would have silently dropped user-visible filtering behavior. Extended the schema (records, loader, env overlay, merger, validator, adapter, legacy translator) as a prerequisite. Also fixedIndexingConfig.parallelism: String → Integer(null = auto-detect sentinel).Phase 2 — migrate + delete
Analyzer(3 call sites) — injectCodeIqUnifiedConfig, replaceProjectConfigLoader.loadProjectConfig(root)with direct reads ofunified.indexing()+unified.detectors().CliOutput.configureFromOptions— drop the redundantloadIfPresentreload. Values already populated on the injected bean at startup. Also dropped the now-unusedrootparameter (updatedAnalyzeCommand,IndexCommand).ProjectConfigLoaderApplyOverridesTest— ported to the unified pipeline (ConfigResolver → UnifiedConfigAdapter). Dropped 5 legacy-only tests (hyphenated filename variants,loadIfPresentreturn-false semantics).ConfigDrivenPipelineTestdeleted (superseded by unified-pipeline coverage).ProjectConfigLoaderstatic API deleted (loadIfPresent,loadProjectConfig, publicparseProjectConfig); legacyio.github.randomcodespace.iq.config.ProjectConfigPOJO deleted (orphaned).Post-change
ProjectConfigLoadersurfaceloadFrom(Path) → LoadResult— the only public loader method.Commits
478d551feat(config): extend unified tree with detectors.categories, detectors.include, indexing.parsers2d5d4aerefactor(analyzer): drop ProjectConfigLoader reload, read filters from CodeIqUnifiedConfig6d7e434refactor(cli): drop redundant ProjectConfigLoader reload in CliOutputc161312refactor(test): port ProjectConfigLoaderApplyOverridesTest to unified config pipeline9d2b415refactor(test): delete ConfigDrivenPipelineTest (superseded by unified-pipeline tests)0cbc924refactor(config): delete legacy static ProjectConfigLoader API + orphaned ProjectConfig POJOTests
Notable behavior changes
.code-iq.yml/.code-iq.yamlfilename variants no longer recognized. Undocumented aliases; repo conventions always usedcodeiq.yml. Flag here if any deployment relied on them.codeiq.yml— malformedmax_depththrowsConfigLoadExceptionwith field path. Legacy.osscodeiq.ymlpath retains lenient coercion (silent null) to minimize migration friction during the one-release deprecation window.Follow-ups (tracked)
CodeIqConfigsetters (task phase a/vuln scan #49 — now unblocked)SQL_ENTITYNodeKind (task phase a/fix playwright webserver #48)UnifiedConfigBeansTestto avoid full@SpringBootTestcontext (task fix(deps): clear all 12 known CVEs from the 2026-04-17 baseline #50)Test plan
mvn -B teston merge commit reports 3272 pass.osscodeiq.ymlwith legacy flatdetector_categories: [java]still filters correctly (via the shim translator)codeiq.ymlwith `indexing: { parsers: [javaparser, antlr] }` scopes parser selection correctlycodeiq.ymlusers see no behavior change🤖 Generated with Claude Code