mirror of
https://github.com/Dvorinka/Devour.git
synced 2026-06-03 20:13:03 +00:00
i dont like commits
This commit is contained in:
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"batch": "Architecture & Coupling",
|
||||
"batch_index": 1,
|
||||
"assessments": {
|
||||
"cross_module_architecture": 82.0
|
||||
},
|
||||
"dimension_notes": {
|
||||
"cross_module_architecture": {
|
||||
"evidence": [
|
||||
"`internal/quality/enhanced_types.go` centralizes many unrelated boundary contracts (scoring metrics, detector transparency, narrative strategy/tools, debt tracking, config) in one package-level type hub.",
|
||||
"`internal/quality/types.go` also acts as a second broad contract hub (findings, scan result, scorecard, language/config, extraction structs), overlapping the same ownership area as `enhanced_types.go` instead of separating by subdomain.",
|
||||
"`internal/quality/scoring_test.go` consumes these shared package-level contracts directly, which reinforces coupling to a wide internal surface rather than narrower scorer-specific interfaces/types."
|
||||
],
|
||||
"impact_scope": "module",
|
||||
"fix_scope": "multi_file_refactor",
|
||||
"confidence": "high"
|
||||
}
|
||||
},
|
||||
"findings": [
|
||||
{
|
||||
"dimension": "cross_module_architecture",
|
||||
"identifier": "quality_package_contract_hub_coupling",
|
||||
"summary": "Quality contracts are concentrated in broad type hubs, creating a coupling hotspot.",
|
||||
"related_files": [
|
||||
"internal/quality/enhanced_types.go",
|
||||
"internal/quality/types.go",
|
||||
"internal/quality/scoring_test.go"
|
||||
],
|
||||
"evidence": [
|
||||
"`enhanced_types.go` and `types.go` both define large cross-cutting models for multiple concerns (analysis narrative, scoring, detector stats, config, extraction metadata) under one package boundary.",
|
||||
"The two files blur subdomain ownership, so edits to one concern can force unrelated consumers in the same package to track evolving shared structs.",
|
||||
"Scoring tests rely on shared package contracts rather than a tighter scorer-local contract, indicating broad internal API exposure."
|
||||
],
|
||||
"suggestion": "Split `internal/quality` contracts by bounded concern (for example: `qualitycore` findings/scan types, `qualityscore` scorecard/metrics, `qualitynarrative` narrative/report DTOs) and keep scorer-facing types in a narrow subpackage/API. Migrate tests to import only scorer-relevant types to reduce transitive coupling.",
|
||||
"confidence": "high",
|
||||
"impact_scope": "module",
|
||||
"fix_scope": "multi_file_refactor"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
{
|
||||
"batch": "Abstractions & Dependencies",
|
||||
"batch_index": 2,
|
||||
"assessments": {
|
||||
"abstraction_fitness": 72.0
|
||||
},
|
||||
"dimension_notes": {
|
||||
"abstraction_fitness": {
|
||||
"evidence": [
|
||||
"Four external scrapers (Astro, Docker, Cloudflare, Nuxt) each reimplement the same transport/change-detection skeleton (`fetchPage`, `DetectChanges`, `generateHash`, per-page `Document` assembly) with only parser/model differences.",
|
||||
"`cmd/serve.go` RPC path for `devour_scrape` mutates CLI globals (`scrapeFormat`, `scrapeOutput`, `scrapeAllowEmpty`) to call `scrapeOne` from `cmd/scrape.go`, showing a leaky abstraction where server flow depends on CLI stateful wiring.",
|
||||
"`vector.Store` advertises interchangeable backends, but `NewStore` can return `ChromemStore` whose methods are all unimplemented runtime errors, so the abstraction surface overstates usable implementations."
|
||||
],
|
||||
"impact_scope": "subsystem",
|
||||
"fix_scope": "multi_file_refactor",
|
||||
"confidence": "high",
|
||||
"sub_axes": {
|
||||
"abstraction_leverage": 68.0,
|
||||
"indirection_cost": 73.0,
|
||||
"interface_honesty": 70.0
|
||||
}
|
||||
}
|
||||
},
|
||||
"findings": [
|
||||
{
|
||||
"dimension": "abstraction_fitness",
|
||||
"identifier": "duplicated_external_scraper_skeleton",
|
||||
"summary": "External docs scrapers duplicate the same orchestration instead of sharing one adapter base",
|
||||
"related_files": [
|
||||
"internal/scraper/external/astrodocs.go",
|
||||
"internal/scraper/external/cloudflaredocs.go",
|
||||
"internal/scraper/external/dockerdocs.go",
|
||||
"internal/scraper/external/nuxtdocs.go"
|
||||
],
|
||||
"evidence": [
|
||||
"Each scraper defines near-identical `fetchPage`, `DetectChanges`, and `generateHash` logic.",
|
||||
"Each `Scrape` method repeats the same flow: validate URL -> fetch HTML -> parser call -> append main doc + sub-doc loop(s).",
|
||||
"Differences are mostly parser/model-specific mapping, but transport/error/hash logic is copy-pasted."
|
||||
],
|
||||
"suggestion": "Introduce a shared docs-scraper base (or helper pipeline) for HTTP fetch + hashing + standard error handling, and keep only parser-specific mapping in per-provider adapters.",
|
||||
"confidence": "high",
|
||||
"impact_scope": "subsystem",
|
||||
"fix_scope": "multi_file_refactor"
|
||||
},
|
||||
{
|
||||
"dimension": "abstraction_fitness",
|
||||
"identifier": "scrape_api_leaks_cli_state",
|
||||
"summary": "Server scrape RPC depends on mutable CLI globals to reuse scrape pipeline",
|
||||
"related_files": [
|
||||
"cmd/serve.go",
|
||||
"cmd/scrape.go",
|
||||
"cmd/get.go"
|
||||
],
|
||||
"evidence": [
|
||||
"`handleServeMethod` temporarily rewrites `scrapeFormat`, `scrapeOutput`, and `scrapeAllowEmpty` before calling `scrapeOne`, then restores them.",
|
||||
"`scrapeOne` is not a pure service API; it is coupled to CLI-level shared state and output behavior.",
|
||||
"`cmd/get.go` also routes through `runScrape`, reinforcing that scraping orchestration is command-centric rather than a reusable application service."
|
||||
],
|
||||
"suggestion": "Extract a stateless scrape service function (explicit request struct + options) used by both CLI commands and RPC handlers; keep CLI flags as translation-only at command boundary.",
|
||||
"confidence": "high",
|
||||
"impact_scope": "subsystem",
|
||||
"fix_scope": "architectural_change"
|
||||
},
|
||||
{
|
||||
"dimension": "abstraction_fitness",
|
||||
"identifier": "vector_store_interface_overpromises",
|
||||
"summary": "Vector store abstraction exposes backends that are selectable but not actually implemented",
|
||||
"related_files": [
|
||||
"internal/vector/store.go",
|
||||
"internal/indexer/indexer.go"
|
||||
],
|
||||
"evidence": [
|
||||
"`NewStore` can return `ChromemStore` when config type is `chromem`.",
|
||||
"All `ChromemStore` interface methods currently return `not implemented` errors.",
|
||||
"`Indexer` depends only on `vector.Store`, so backend failure appears at runtime after abstraction selection instead of at wiring/validation time."
|
||||
],
|
||||
"suggestion": "Make backend capabilities explicit: either remove/guard `chromem` selection until complete, or return an initialization error type from store construction and enforce backend readiness before indexing starts.",
|
||||
"confidence": "high",
|
||||
"impact_scope": "module",
|
||||
"fix_scope": "multi_file_refactor"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
{
|
||||
"batch": "Governance & Contracts",
|
||||
"batch_index": 3,
|
||||
"assessments": {
|
||||
"cross_module_architecture": 81.0,
|
||||
"test_strategy": 69.0
|
||||
},
|
||||
"dimension_notes": {
|
||||
"cross_module_architecture": {
|
||||
"evidence": [
|
||||
"README.md defines the quality model publicly as 5 mechanical + 7 subjective dimensions, implying a stable external contract for score interpretation.",
|
||||
"internal/quality/enhanced_types.go defines additional dimensions (e.g., DimensionElegance, DimensionContracts) that are not reflected in README governance docs.",
|
||||
"internal/quality/types.go exposes status/state enums (including StatusIgnored) that are absent from README user-facing resolution policy examples, creating docs-vs-runtime boundary drift."
|
||||
],
|
||||
"impact_scope": "codebase",
|
||||
"fix_scope": "architectural_change",
|
||||
"confidence": "medium"
|
||||
},
|
||||
"test_strategy": {
|
||||
"evidence": [
|
||||
"internal/quality/scoring_test.go is heavily unit-focused and validates scorer internals, but does not validate public contract stability between quality types and README-documented behavior.",
|
||||
"README.md publishes CLI and JSON-RPC command contracts, but assigned tests do not exercise those published interfaces as compatibility gates.",
|
||||
"pkg/rustdocs/parser_test.go and internal/quality/scoring_test.go include brittle assertions (fixed positional result indexing and strict output text matching) that couple tests to implementation/presentation details."
|
||||
],
|
||||
"impact_scope": "subsystem",
|
||||
"fix_scope": "multi_file_refactor",
|
||||
"confidence": "high"
|
||||
}
|
||||
},
|
||||
"findings": [
|
||||
{
|
||||
"dimension": "cross_module_architecture",
|
||||
"identifier": "docs_runtime_quality_contract_drift",
|
||||
"summary": "Quality dimensions/statuses drift between public docs and runtime model contracts.",
|
||||
"related_files": [
|
||||
"README.md",
|
||||
"internal/quality/enhanced_types.go",
|
||||
"internal/quality/types.go"
|
||||
],
|
||||
"evidence": [
|
||||
"README.md frames score interpretation around a specific dimension set and user workflow.",
|
||||
"internal/quality/enhanced_types.go includes extra dimension constants not represented in README contract text.",
|
||||
"internal/quality/types.go includes StatusIgnored while README resolution examples only expose fixed/wontfix/false_positive paths."
|
||||
],
|
||||
"suggestion": "Define a single versioned public quality contract (dimensions + statuses) as source-of-truth, generate README contract tables from it, and add a CI check that fails when exported enums and published docs diverge.",
|
||||
"confidence": "medium",
|
||||
"impact_scope": "codebase",
|
||||
"fix_scope": "architectural_change"
|
||||
},
|
||||
{
|
||||
"dimension": "test_strategy",
|
||||
"identifier": "missing_public_contract_compat_tests",
|
||||
"summary": "Published CLI/RPC governance contracts are not protected by compatibility tests.",
|
||||
"related_files": [
|
||||
"README.md",
|
||||
"internal/quality/scoring_test.go",
|
||||
"internal/quality/types.go"
|
||||
],
|
||||
"evidence": [
|
||||
"README.md documents stable command and RPC method surfaces for users.",
|
||||
"internal/quality/scoring_test.go covers scoring behavior but not end-to-end contract assertions tied to documented surfaces.",
|
||||
"No assigned test verifies that externally documented score/status semantics remain compatible with exported model types."
|
||||
],
|
||||
"suggestion": "Add contract tests that parse/validate documented command and RPC surface claims against runtime registration/types, and add schema-level golden tests for serialized quality/status payloads.",
|
||||
"confidence": "high",
|
||||
"impact_scope": "codebase",
|
||||
"fix_scope": "multi_file_refactor"
|
||||
},
|
||||
{
|
||||
"dimension": "test_strategy",
|
||||
"identifier": "brittle_assertions_on_order_and_formatting",
|
||||
"summary": "Tests are fragile due to strict ordering and presentation-string coupling.",
|
||||
"related_files": [
|
||||
"internal/quality/scoring_test.go",
|
||||
"pkg/rustdocs/parser_test.go"
|
||||
],
|
||||
"evidence": [
|
||||
"pkg/rustdocs/parser_test.go asserts semantic expectations through fixed indexes (results[0], results[1], results[2]) rather than identity-based matching.",
|
||||
"internal/quality/scoring_test.go asserts many exact output substrings in FormatScorecard, coupling tests to formatting text that can change without behavioral regressions."
|
||||
],
|
||||
"suggestion": "Refactor tests to assert semantic invariants (presence by key/kind, normalized structured fields) and reserve strict golden-output checks for explicitly versioned presentation contracts.",
|
||||
"confidence": "high",
|
||||
"impact_scope": "module",
|
||||
"fix_scope": "multi_file_refactor"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
{
|
||||
"batch": "Design Coherence \u2014 Mechanical Concern Signals",
|
||||
"batch_index": 4,
|
||||
"assessments": {
|
||||
"design_coherence": 74.0
|
||||
},
|
||||
"dimension_notes": {
|
||||
"design_coherence": {
|
||||
"evidence": [
|
||||
"Command passthrough wrappers add non-functional indirection in language command modules: `languages/dart/commands.py` defines `_cmd_*_impl` plus thin `cmd_*` forwarders for each command (`cmd_large`, `cmd_complexity`, `cmd_deps`, `cmd_cycles`, `cmd_orphaned`, `cmd_dupes`).",
|
||||
"C# deps module mixes parsing, graph construction, CLI arg resolution, and terminal rendering in one file (`languages/csharp/detectors/deps.py` contains core graph builders and also `cmd_deps`/`cmd_cycles` UI handlers).",
|
||||
"Status rendering duplicates score-bar construction logic in two loops in `app/commands/status_parts/render.py` (same threshold/color/filled computation blocks around lines ~191-199 and ~223-231), increasing drift risk."
|
||||
],
|
||||
"impact_scope": "subsystem",
|
||||
"fix_scope": "multi_file_refactor",
|
||||
"confidence": "high"
|
||||
}
|
||||
},
|
||||
"findings": [
|
||||
{
|
||||
"dimension": "design_coherence",
|
||||
"identifier": "passthrough_command_wrappers_add_low_leverage_layers",
|
||||
"summary": "Language command modules include thin forwarding wrappers with no behavioral value.",
|
||||
"related_files": [
|
||||
"desloppify/desloppify/desloppify/languages/dart/commands.py",
|
||||
"desloppify/desloppify/desloppify/languages/csharp/commands.py",
|
||||
"desloppify/desloppify/desloppify/languages/framework/commands_base.py"
|
||||
],
|
||||
"evidence": [
|
||||
"`languages/dart/commands.py` creates `_cmd_*_impl` callables and then defines six `cmd_*` functions that only call the corresponding impl.",
|
||||
"`languages/csharp/commands.py` also keeps thin wrappers (`cmd_large`, `cmd_complexity`, `cmd_deps`, `cmd_cycles`) that forward directly to other callables.",
|
||||
"The framework already provides factory-returned callables; wrapper layers increase symbol count and call depth without adding policy."
|
||||
],
|
||||
"suggestion": "Assign factory outputs directly to exported command names (or build the registry directly from generated callables) and keep wrappers only where they add language-specific behavior, validation, or formatting.",
|
||||
"confidence": "high",
|
||||
"impact_scope": "module",
|
||||
"fix_scope": "multi_file_refactor"
|
||||
},
|
||||
{
|
||||
"dimension": "design_coherence",
|
||||
"identifier": "csharp_deps_module_blends_core_and_cli_responsibilities",
|
||||
"summary": "C# dependency detector file combines analysis engine logic with CLI presentation.",
|
||||
"related_files": [
|
||||
"desloppify/desloppify/desloppify/languages/csharp/detectors/deps.py",
|
||||
"desloppify/desloppify/desloppify/languages/csharp/commands.py",
|
||||
"desloppify/desloppify/desloppify/languages/_shared/scaffold_detect_commands.py"
|
||||
],
|
||||
"evidence": [
|
||||
"`languages/csharp/detectors/deps.py` includes internal graph/parsing functions (`_parse_project_assets_references`, `_build_dep_graph_roslyn`, `build_dep_graph`) and command handlers (`cmd_deps`, `cmd_cycles`) in the same module.",
|
||||
"`languages/csharp/commands.py` forwards to `cmd_deps_direct`/`cmd_cycles_deps`, meaning command routing depends on detector-module UI functions instead of a clean detector API.",
|
||||
"Other language paths use shared command scaffolding (`languages/_shared/scaffold_detect_commands.py`) that separates command shell concerns from graph/detection logic."
|
||||
],
|
||||
"suggestion": "Split C# deps into `detectors/deps_core.py` (graph/parsing only) and command-facing adapters in `commands.py` (or scaffold factories), so detectors expose data and command modules own JSON/table rendering.",
|
||||
"confidence": "high",
|
||||
"impact_scope": "subsystem",
|
||||
"fix_scope": "architectural_change"
|
||||
},
|
||||
{
|
||||
"dimension": "design_coherence",
|
||||
"identifier": "status_bar_render_logic_duplicated_in_two_paths",
|
||||
"summary": "Status renderer repeats identical score-bar construction for mechanical and subjective rows.",
|
||||
"related_files": [
|
||||
"desloppify/desloppify/desloppify/app/commands/status_parts/render.py",
|
||||
"desloppify/desloppify/desloppify/app/output/scorecard_parts/projection.py"
|
||||
],
|
||||
"evidence": [
|
||||
"`show_dimension_table` in `status_parts/render.py` computes `filled`, score thresholds, and colored bar in one loop for mechanical dimensions and repeats the same logic in a second loop for subjective entries.",
|
||||
"Duplicated threshold constants (`>=98`, `>=93`) and color composition appear in both blocks, creating a two-site maintenance point for one rendering policy."
|
||||
],
|
||||
"suggestion": "Extract a shared `render_score_bar(score_val, bar_len)` helper (or move the row formatting policy into scorecard projection/output helpers) and reuse it for both loops to keep display semantics consistent.",
|
||||
"confidence": "high",
|
||||
"impact_scope": "module",
|
||||
"fix_scope": "single_edit"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
{
|
||||
"batch": "Cross-cutting Sweep",
|
||||
"batch_index": 5,
|
||||
"assessments": {
|
||||
"error_consistency": 68.0
|
||||
},
|
||||
"dimension_notes": {
|
||||
"error_consistency": {
|
||||
"evidence": [
|
||||
"RPC paths mix strict and lax decode behavior: `cmd/serve.go` returns decode errors for `devour_scrape`/`devour_ask` but ignores decode errors for `devour_query` and `devour_sync` (`_ = json.Unmarshal(...)`).",
|
||||
"`cmd/serve.go` `devour_status` ignores errors from `LoadSourceState` and `EnsureIndexed` then dereferences `idxStats.Documents`, which can panic on nil when indexing fails.",
|
||||
"`internal/server/server.go` exposes raw internal errors to clients (`Message: err.Error()`), while parse/invalid-request errors are normalized strings; HTTP transport always emits 400 for any RPC error, collapsing error classes.",
|
||||
"`internal/ai/openai.go` does not check HTTP status before JSON decode, unlike scraper fetchers in `internal/scraper/external/*.go` and `internal/scraper/openapi.go` that explicitly gate on status codes.",
|
||||
"`internal/search/engine.go` and `internal/scraper/openapi.go` mix wrapped and passthrough errors in adjacent paths, producing uneven context for operators."
|
||||
],
|
||||
"impact_scope": "subsystem",
|
||||
"fix_scope": "multi_file_refactor",
|
||||
"confidence": "high"
|
||||
}
|
||||
},
|
||||
"findings": [
|
||||
{
|
||||
"dimension": "error_consistency",
|
||||
"identifier": "rpc_decode_and_response_contract_drift",
|
||||
"summary": "RPC methods use inconsistent decode and error-response contracts",
|
||||
"related_files": [
|
||||
"cmd/serve.go",
|
||||
"internal/server/server.go"
|
||||
],
|
||||
"evidence": [
|
||||
"`cmd/serve.go` ignores JSON decode errors in `devour_query`/`devour_sync` but returns decode errors in `devour_scrape`/`devour_ask`.",
|
||||
"`internal/server/server.go` returns raw `err.Error()` in RPC payloads and maps all RPC errors to HTTP 400 in `writeRPC`."
|
||||
],
|
||||
"suggestion": "Define one RPC error policy: always validate/decode params the same way, map known classes to stable RPC codes/messages, and map transport HTTP statuses by error class (client input vs internal failure).",
|
||||
"confidence": "high",
|
||||
"impact_scope": "subsystem",
|
||||
"fix_scope": "multi_file_refactor"
|
||||
},
|
||||
{
|
||||
"dimension": "error_consistency",
|
||||
"identifier": "serve_status_swallows_errors_then_dereferences_nil",
|
||||
"summary": "Status handler ignores errors and can panic from nil stats",
|
||||
"related_files": [
|
||||
"cmd/serve.go",
|
||||
"internal/search/engine.go"
|
||||
],
|
||||
"evidence": [
|
||||
"`cmd/serve.go` uses `state, _ := projectstate.LoadSourceState(...)` and `idxStats, _ := engine.EnsureIndexed(ctx)` in `devour_status`.",
|
||||
"The same block unconditionally reads `idxStats.Documents` and `idxStats.LastIndexedAt`, which is unsafe if `EnsureIndexed` returned an error."
|
||||
],
|
||||
"suggestion": "Handle both errors explicitly in `devour_status`; return structured partial-status with an error field or fail the method uniformly, but do not ignore and dereference.",
|
||||
"confidence": "high",
|
||||
"impact_scope": "module",
|
||||
"fix_scope": "single_edit"
|
||||
},
|
||||
{
|
||||
"dimension": "error_consistency",
|
||||
"identifier": "openai_http_error_path_not_normalized",
|
||||
"summary": "OpenAI client lacks explicit HTTP status error handling",
|
||||
"related_files": [
|
||||
"internal/ai/openai.go",
|
||||
"internal/scraper/openapi.go",
|
||||
"internal/scraper/external/astrodocs.go"
|
||||
],
|
||||
"evidence": [
|
||||
"`internal/ai/openai.go` decodes response bodies directly and only checks `embeddingResp.Error`/`chatResp.Error`; non-2xx responses without expected JSON become generic decode errors.",
|
||||
"`internal/scraper/openapi.go` and external scrapers explicitly validate HTTP status before body parsing and return explicit HTTP status errors."
|
||||
],
|
||||
"suggestion": "Add explicit non-2xx handling in both OpenAI request paths: include status code, bounded response body excerpt, and endpoint context before JSON decode.",
|
||||
"confidence": "high",
|
||||
"impact_scope": "module",
|
||||
"fix_scope": "multi_file_refactor"
|
||||
},
|
||||
{
|
||||
"dimension": "error_consistency",
|
||||
"identifier": "mixed_wrapping_vs_passthrough_in_core_flows",
|
||||
"summary": "Adjacent paths alternate between wrapped and raw error returns",
|
||||
"related_files": [
|
||||
"internal/search/engine.go",
|
||||
"internal/scraper/openapi.go",
|
||||
"internal/config/config.go"
|
||||
],
|
||||
"evidence": [
|
||||
"`internal/search/engine.go` frequently returns raw errors (`return nil, err`) from filesystem/index operations.",
|
||||
"`internal/scraper/openapi.go` similarly passes through request/file errors raw in `readSpec`, while other branches wrap with operation context.",
|
||||
"`internal/config/config.go` demonstrates contextual wrapping style (`read config`, `parse config`), creating drift against less-informative paths."
|
||||
],
|
||||
"suggestion": "Adopt a package-level rule: wrap external boundary failures with operation context (read/write/parse/network) and preserve `%w`; apply consistently across search/openapi paths.",
|
||||
"confidence": "medium",
|
||||
"impact_scope": "subsystem",
|
||||
"fix_scope": "multi_file_refactor"
|
||||
},
|
||||
{
|
||||
"dimension": "error_consistency",
|
||||
"identifier": "scanner_pipeline_fail_open_is_inconsistent",
|
||||
"summary": "Quality scan path mixes fail-open and fail-fast behaviors",
|
||||
"related_files": [
|
||||
"internal/quality/scanner.go",
|
||||
"internal/quality/plugins/go/analyzers/test_coverage.go",
|
||||
"internal/quality/plugins/go/analyzers/detectors.go"
|
||||
],
|
||||
"evidence": [
|
||||
"`internal/quality/scanner.go` logs detector failures and continues, silently reducing coverage of reported findings.",
|
||||
"`test_coverage.go` returns `(nil, nil)` for missing `go` tool or missing generated coverage file, while other detector failures return explicit errors.",
|
||||
"`detectors.go` has parse/count paths that silently `continue` on per-file errors, further mixing behavior."
|
||||
],
|
||||
"suggestion": "Standardize detector error semantics with typed outcomes (hard error, soft-skip with reason, per-file skip count) and surface these in scan results so degraded scans are explicit.",
|
||||
"confidence": "medium",
|
||||
"impact_scope": "subsystem",
|
||||
"fix_scope": "architectural_change"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
{
|
||||
"batch": "Full Codebase Sweep",
|
||||
"batch_index": 6,
|
||||
"assessments": {
|
||||
"cross_module_architecture": 72.0,
|
||||
"error_consistency": 70.0,
|
||||
"abstraction_fitness": 68.0,
|
||||
"test_strategy": 64.0,
|
||||
"design_coherence": 69.0
|
||||
},
|
||||
"dimension_notes": {
|
||||
"cross_module_architecture": {
|
||||
"evidence": [
|
||||
"cmd/serve.go calls command handlers directly (runSync, scrapeOne) and mutates command-level globals (scrapeFormat/scrapeOutput/scrapeAllowEmpty and syncForce/syncRebuild/syncSource) before invoking them, coupling RPC transport to CLI flag state.",
|
||||
"Source-type detection logic exists in both internal/scraper/scraper.go:92 (DetectSourceType) and cmd/scrape.go:314 (detectSourceType), creating boundary drift for core classification behavior."
|
||||
],
|
||||
"impact_scope": "subsystem",
|
||||
"fix_scope": "architectural_change",
|
||||
"confidence": "high"
|
||||
},
|
||||
"error_consistency": {
|
||||
"evidence": [
|
||||
"cmd/serve.go suppresses parse and subsystem errors via `_ = json.Unmarshal(...)` and `state, _ := projectstate.LoadSourceState(...)` / `idxStats, _ := engine.EnsureIndexed(...)`, while sibling paths return wrapped errors.",
|
||||
"Startup failure behavior differs across modules: cmd/root.go exits process with os.Exit(1), while internal/quality/plugins/go/plugin.go init() panics on registration failure."
|
||||
],
|
||||
"impact_scope": "subsystem",
|
||||
"fix_scope": "multi_file_refactor",
|
||||
"confidence": "high"
|
||||
},
|
||||
"abstraction_fitness": {
|
||||
"evidence": [
|
||||
"Most external scraper implementations repeat near-identical transport/change-detection scaffolding (`fetchPage`, `DetectChanges`, `generateHash`) across files such as internal/scraper/external/reactdocs.go, tsdocs.go, godocs.go, rustdocs.go, and cloudflaredocs.go.",
|
||||
"This repeated wrapper structure adds maintenance indirection without policy variance (same HTTP GET + user-agent + status check + body read flow)."
|
||||
],
|
||||
"impact_scope": "subsystem",
|
||||
"fix_scope": "architectural_change",
|
||||
"confidence": "high",
|
||||
"sub_axes": {
|
||||
"abstraction_leverage": 61.0,
|
||||
"indirection_cost": 43.0,
|
||||
"interface_honesty": 74.0
|
||||
}
|
||||
},
|
||||
"test_strategy": {
|
||||
"evidence": [
|
||||
"High-impact command flows lack direct tests: cmd/serve.go, cmd/sync.go, cmd/query.go, cmd/push.go, cmd/verify.go have no file-level tests while they orchestrate indexing/scraping/status behavior.",
|
||||
"Most external scrapers are untested at integration unit level (e.g., internal/scraper/external/{godocs,rustdocs,reactdocs,cloudflaredocs,nuxtdocs,...}.go) even though they include custom parsing-to-document mapping and network error handling."
|
||||
],
|
||||
"impact_scope": "codebase",
|
||||
"fix_scope": "multi_file_refactor",
|
||||
"confidence": "high"
|
||||
},
|
||||
"design_coherence": {
|
||||
"evidence": [
|
||||
"cmd/serve.go:71-210 centralizes multiple unrelated workflows (query/status/scrape/ask/sync) in one switch, with request parsing, domain orchestration, and response formatting mixed in a single function.",
|
||||
"The same function also performs cross-command mutable state choreography (temporarily overriding scrape/sync globals), combining transport logic with command execution mechanics."
|
||||
],
|
||||
"impact_scope": "module",
|
||||
"fix_scope": "multi_file_refactor",
|
||||
"confidence": "high"
|
||||
}
|
||||
},
|
||||
"findings": [
|
||||
{
|
||||
"dimension": "cross_module_architecture",
|
||||
"identifier": "rpc_cli_global_state_coupling",
|
||||
"summary": "RPC handlers mutate CLI global flags to execute workflows across command boundaries.",
|
||||
"related_files": [
|
||||
"cmd/serve.go",
|
||||
"cmd/scrape.go",
|
||||
"cmd/sync.go"
|
||||
],
|
||||
"evidence": [
|
||||
"cmd/serve.go sets scrapeFormat/scrapeOutput/scrapeAllowEmpty before calling scrapeOne and restores afterward.",
|
||||
"cmd/serve.go sets syncForce/syncRebuild/syncSource before calling runSync and restores afterward."
|
||||
],
|
||||
"suggestion": "Extract scrape/sync/query use-cases into stateless service functions (input structs + return structs), call them from both Cobra commands and RPC handlers, and remove shared mutable command globals from runtime execution paths.",
|
||||
"confidence": "high",
|
||||
"impact_scope": "subsystem",
|
||||
"fix_scope": "architectural_change"
|
||||
},
|
||||
{
|
||||
"dimension": "error_consistency",
|
||||
"identifier": "silent_error_drops_in_rpc_paths",
|
||||
"summary": "Several RPC paths ignore parse/index/state errors, producing inconsistent failure contracts.",
|
||||
"related_files": [
|
||||
"cmd/serve.go",
|
||||
"internal/search/engine.go",
|
||||
"internal/projectstate/state.go"
|
||||
],
|
||||
"evidence": [
|
||||
"cmd/serve.go ignores JSON unmarshal errors for devour_query/devour_sync (`_ = json.Unmarshal(...)`).",
|
||||
"cmd/serve.go ignores errors from LoadSourceState and EnsureIndexed, yet reads fields from returned values.",
|
||||
"Other command paths generally propagate wrapped errors with `%w`."
|
||||
],
|
||||
"suggestion": "Treat request decode, source-state load, and index-check failures uniformly: return explicit wrapped errors from each branch and avoid underscore-discarded errors in RPC handlers.",
|
||||
"confidence": "high",
|
||||
"impact_scope": "subsystem",
|
||||
"fix_scope": "single_edit"
|
||||
},
|
||||
{
|
||||
"dimension": "abstraction_fitness",
|
||||
"identifier": "external_scraper_transport_duplication",
|
||||
"summary": "External scrapers duplicate the same HTTP fetch/hash/change-detection boilerplate.",
|
||||
"related_files": [
|
||||
"internal/scraper/external/reactdocs.go",
|
||||
"internal/scraper/external/tsdocs.go",
|
||||
"internal/scraper/external/godocs.go",
|
||||
"internal/scraper/external/rustdocs.go",
|
||||
"internal/scraper/external/cloudflaredocs.go"
|
||||
],
|
||||
"evidence": [
|
||||
"Each scraper reimplements equivalent `fetchPage` with identical request/header/response-body flow.",
|
||||
"Each scraper reimplements nearly identical `DetectChanges` and `generateHash` logic."
|
||||
],
|
||||
"suggestion": "Introduce a shared base helper (e.g., `fetchPage`, `contentHash`, `detectChanges`) in internal/scraper/external/types.go or a dedicated internal transport module, then keep per-scraper files focused on parser-to-document mapping.",
|
||||
"confidence": "high",
|
||||
"impact_scope": "subsystem",
|
||||
"fix_scope": "multi_file_refactor"
|
||||
},
|
||||
{
|
||||
"dimension": "test_strategy",
|
||||
"identifier": "missing_tests_on_orchestration_and_adapters",
|
||||
"summary": "Critical orchestration commands and most external adapters have no direct tests.",
|
||||
"related_files": [
|
||||
"cmd/serve.go",
|
||||
"cmd/sync.go",
|
||||
"cmd/query.go",
|
||||
"internal/scraper/external/godocs.go",
|
||||
"internal/scraper/external/reactdocs.go"
|
||||
],
|
||||
"evidence": [
|
||||
"No *_test.go peers for cmd/serve.go, cmd/sync.go, cmd/query.go despite high-risk orchestration behavior.",
|
||||
"Only one external scraper has direct tests while many adapter implementations contain custom mapping and error-path logic."
|
||||
],
|
||||
"suggestion": "Add table-driven tests for RPC method branches and error propagation in cmd/serve.go, plus httptest-based adapter contract tests covering fetch failures, parser errors, and document mapping for each external scraper family.",
|
||||
"confidence": "high",
|
||||
"impact_scope": "codebase",
|
||||
"fix_scope": "multi_file_refactor"
|
||||
},
|
||||
{
|
||||
"dimension": "design_coherence",
|
||||
"identifier": "serve_handler_multi_responsibility_switch",
|
||||
"summary": "Single handler function mixes transport, parsing, orchestration, and mutable state management.",
|
||||
"related_files": [
|
||||
"cmd/serve.go",
|
||||
"cmd/scrape.go",
|
||||
"cmd/sync.go",
|
||||
"cmd/query.go"
|
||||
],
|
||||
"evidence": [
|
||||
"handleServeMethod contains method routing plus per-method request schemas, domain calls, and response shaping in one body.",
|
||||
"The function coordinates temporary mutation of command globals to reuse CLI code paths."
|
||||
],
|
||||
"suggestion": "Split each RPC method into dedicated handler functions (e.g., handleQueryRPC, handleScrapeRPC, handleSyncRPC) that depend on explicit service interfaces instead of command globals.",
|
||||
"confidence": "high",
|
||||
"impact_scope": "module",
|
||||
"fix_scope": "multi_file_refactor"
|
||||
}
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user