{ "batch": "Abstractions & Dependencies", "batch_index": 2, "assessments": { "abstraction_fitness": 68.0 }, "dimension_notes": { "abstraction_fitness": { "evidence": [ "Language-to-doc behavior is spread across multiple large switches: URL construction in cmd/get.go:78-173, type mapping in cmd/get.go:175-205, and term derivation in cmd/ask.go:205-260+.", "External scraper implementations repeat the same transport/change-detection scaffold (config+parser+http client fields, URL check, fetchPage, generateHash, DetectChanges) across multiple files, e.g. internal/scraper/external/godocs.go:17-121, internal/scraper/external/javadocs.go:16-115, internal/scraper/external/nuxtdocs.go:16-120, internal/scraper/external/cloudflaredocs.go:16-105.", "Vector store abstraction exposes implementations that are selected by default config but intentionally unimplemented: internal/config/config.go:121-125 defaults to chromem, while internal/vector/store.go:221-243 returns \"chromem store not implemented\" for all operations.", "Configuration defaults are duplicated in two representations (typed defaults and hand-written YAML template), increasing drift risk: cmd/init.go:92-149 and internal/config/config.go:104-160." ], "impact_scope": "subsystem", "fix_scope": "architectural_change", "confidence": "high", "sub_axes": { "abstraction_leverage": 62.0, "indirection_cost": 71.0, "interface_honesty": 60.0 } } }, "findings": [ { "dimension": "abstraction_fitness", "identifier": "language_catalog_scattered_switches", "summary": "Language routing logic is duplicated across CLI flows instead of one catalog abstraction", "related_files": [ "cmd/get.go", "cmd/ask.go" ], "evidence": [ "cmd/get.go:78-173 defines a large language switch for URL building; cmd/get.go:175-205 defines a second switch for source type mapping.", "cmd/ask.go:205-260+ adds a third language switch for term heuristics, creating three independent sources of truth for one domain model." ], "suggestion": "Introduce a single `LanguageSpec` registry (aliases, source type, URL builder, optional query-term strategy) in one package and have both `get` and `ask` consume it; keep per-language behavior as data/functions attached to that registry.", "confidence": "high", "impact_scope": "subsystem", "fix_scope": "architectural_change" }, { "dimension": "abstraction_fitness", "identifier": "external_scraper_scaffold_duplication", "summary": "External scraper adapters reimplement the same transport/hash lifecycle repeatedly", "related_files": [ "internal/scraper/external/godocs.go", "internal/scraper/external/javadocs.go", "internal/scraper/external/nuxtdocs.go", "internal/scraper/external/cloudflaredocs.go" ], "evidence": [ "Each file defines near-identical struct fields (`config`, `parser`, `client`), constructor wiring, URL-required guard, `fetchPage`, `generateHash`, and `DetectChanges` flow (e.g., godocs.go:17-121 and javadocs.go:16-115).", "Duplication scales linearly with each new source adapter, increasing edit surface for cross-cutting behavior (timeouts, headers, error mapping)." ], "suggestion": "Extract a shared `HTTPDocScraperBase` (or composable helper functions) for request execution, status handling, hashing, and change detection; keep each adapter focused on parser invocation and domain-specific document mapping.", "confidence": "high", "impact_scope": "subsystem", "fix_scope": "multi_file_refactor" }, { "dimension": "abstraction_fitness", "identifier": "default_selects_unimplemented_store", "summary": "Store interface contract is dishonest because default backend is not operational", "related_files": [ "internal/vector/store.go", "internal/config/config.go" ], "evidence": [ "internal/config/config.go:121-125 sets default vector DB type to `chromem`.", "internal/vector/store.go:221-243 returns `chromem store not implemented` for all `Store` operations after `NewStore` can select that backend (store.go:63-72)." ], "suggestion": "Either implement `ChromemStore` before exposing it as default, or switch default to a working backend and gate chromem behind explicit opt-in plus capability check at startup.", "confidence": "high", "impact_scope": "module", "fix_scope": "architectural_change" }, { "dimension": "abstraction_fitness", "identifier": "config_defaults_double_encoded", "summary": "Initialization defaults are encoded twice with different abstractions", "related_files": [ "cmd/init.go", "internal/config/config.go" ], "evidence": [ "cmd/init.go:92-149 hardcodes YAML defaults as a template string.", "internal/config/config.go:104-160 hardcodes defaults again in typed structs, requiring synchronized updates across two representations." ], "suggestion": "Generate init YAML from `config.Default()` via marshal + small post-processing/comments, or maintain a single canonical defaults schema consumed by both loader and init command.", "confidence": "high", "impact_scope": "module", "fix_scope": "multi_file_refactor" } ] }