Skip to content

refactor(analyzer): extract synthesizers + resolution_outcomes into pure cores#169

Merged
zzet merged 1 commit into
mainfrom
refactor/extract-analyzer-cores
Jun 25, 2026
Merged

refactor(analyzer): extract synthesizers + resolution_outcomes into pure cores#169
zzet merged 1 commit into
mainfrom
refactor/extract-analyzer-cores

Conversation

@zzet

@zzet zzet commented Jun 25, 2026

Copy link
Copy Markdown
Owner

What

Extracts the synthesizers and resolution_outcomes analyzers out of their MCP handlers into a new internal/analyzer package as pure calculations (graph in, struct out):

  • AnalyzeSynthesizers
  • AnalyzeResolutionOutcomes / ClassifyUnresolved

handleAnalyzeSynthesizers and handleAnalyzeResolutionOutcomes now delegate to these cores. Output shapes are unchanged — the existing MCP-layer tests pass as-is and are the safety net for the refactor. The resolution-outcome taxonomy constants now live in internal/analyzer as the single source of truth, with thin aliases retained in the mcp package so existing call sites/tests keep compiling.

Provenance

This is the reusable half of #84 by @avfirsov, kept as a co-authored commit. The daemonless gortex analyze CLI from that PR is intentionally not included here: gortex analyze already exists on main as a daemon-routed verb over the full analyze dispatcher (all kinds, --format json|gcx|toon|text, gortex analyze kinds), and a parallel in-process command would both collide with it and cut against the daemon-centric direction. This PR keeps only the part with lasting value — the pure-core extraction and the DRY refactor of the two handlers.

Two reconciliations against current main (both landed after #84's base, so the original PR couldn't see them):

  • The stdlib_header outcome (C/C++/ObjC standard-library angle-includes) is carried into the extracted core, with a matching core-level test.
  • nodeIsDefinitionKind stays in the mcp package because id_resolve.go also depends on it; only classifyUnresolved / sameLanguageFamily move into the analyzer.

Tests

  • internal/analyzer: unit/shape tests for both cores — synthesizer grouping + name filter; the full unresolved-edge taxonomy + reason filter + stdlib_header.
  • Existing internal/mcp analyze handler tests unchanged and green.

go build ./..., go vet, and golangci-lint clean; go test ./internal/analyzer/... ./internal/mcp/... passes (2470 tests).

Running analyze in CI (no resident daemon to babysit)

The original motivation behind #84 was a one-shot, CI-style invocation — "index a path once, get JSON, exit" — e.g. to A/B a fork against baseline. That capability already ships via the daemon-routed gortex analyze; in CI the daemon is ephemeral per-run, so reproducibility is intact. Modeled on examples/.github/workflows/gortex-architecture.yml:

name: gortex-analyze
on: [push, workflow_dispatch]
jobs:
  analyze:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-go@v5
        with:
          go-version: stable

      - name: Install gortex
        run: |
          go install github.com/zzet/gortex/cmd/gortex@latest
          echo "$(go env GOPATH)/bin" >> "$GITHUB_PATH"

      - name: Index + analyze (one-shot)
        run: |
          gortex daemon start --detach
          gortex track --wait .   # blocks until indexing settles
          gortex analyze --kind synthesizers         --format json > synthesizers.json
          gortex analyze --kind resolution_outcomes  --format json > outcomes.json
          gortex daemon stop

      - uses: actions/upload-artifact@v4
        with:
          name: gortex-analysis
          path: |
            synthesizers.json
            outcomes.json

gortex track --wait (PR #170) blocks until the daemon has indexed the repo, so the recipe needs no poll loop. On a build without that flag, replace it with gortex track . followed by a wait — e.g. for i in $(seq 1 60); do gortex status | grep -qE '[1-9][0-9]* nodes' && break; sleep 2; done.

gortex analyze kinds lists every supported kind. For a fork-vs-baseline A/B, run the same steps against each checkout and diff the JSON. On native Windows where two builds run side by side, isolate state per build (separate GORTEX_HOME / socket) rather than reaching for a separate daemonless code path.

…ure cores

Pull the synthesizers and resolution-outcomes analyzers out of the MCP
handlers into a new internal/analyzer package as pure calculations
(graph in, struct out): AnalyzeSynthesizers, AnalyzeResolutionOutcomes,
and ClassifyUnresolved. The taxonomy constants now live in
internal/analyzer as the single source of truth, with thin aliases kept
in the mcp package for existing call sites and tests.

handleAnalyzeSynthesizers and handleAnalyzeResolutionOutcomes now
delegate to the cores; output shapes are unchanged, so the existing
MCP-layer tests are the regression net. The stdlib_header outcome is
carried into the core, and nodeIsDefinitionKind stays in the mcp package
because id_resolve.go also depends on it.

Adds unit tests for both cores: synthesizer grouping + name filter, and
the full unresolved-edge taxonomy + reason filter + stdlib_header.

Co-authored-by: avfirsov <afirsov410@gmail.com>
@zzet zzet merged commit 58c83e7 into main Jun 25, 2026
10 checks passed
@zzet zzet deleted the refactor/extract-analyzer-cores branch June 25, 2026 20:34
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