Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,36 @@

## Unreleased

- Hard-cut Swift, Dart, Scala, and Groovy/Gradle onto version-1 qualifying
universal evidence pipelines. The bounded AST-first producer publishes
declarations, scopes, bindings, occurrences, and conservative relationship
candidates with exact language constraints; Swift Vapor routes now use the
`vapor-swift` evidence-backed pack, bounded `pubspec.yaml`/`build.sbt`/
`Package.swift`/Gradle project metadata participates in fingerprints, and
legacy Swift member-table plus broad JVM stub rewiring no longer selects
targets for these languages.

- Complete the independent SwiftSyntax, Dart Analyzer, scala.meta, and Groovy
CompilationUnit qualification providers. Clean pinned Swift, Dart, Scala,
and Groovy corpora now pass the graph-backed precision/recall audits and
fixture performance gates; the four production pipelines remain
`Qualifying` pending a separate promotion decision.

- Turn the VS Code codebase query view into a multi-command workbench with
separate Ask, Explain, and CompassQL composers and durable result tabs.
Typed Ask diagnostics, symbol relationships, source links, and CompassQL rows
now render as readable UI instead of raw JSON. Typed `compass ask` also
accepts `--at REV` for immutable revision graphs.

- Let VS Code users open a call graph by entering a function name, qualified
name, or stable symbol ID in the Call Graph pane, with callers, callees, or
both selectable before tracing. The existing cursor workflow remains
available in the same pane.

- Keep Codebase Evolution strict when a stored revision uses an unsupported
artifact layout, and offer to rebuild the affected revision with the current
Compass version instead of mapping legacy history records.

- Make community detail graphs easier to scan in both exported HTML and VS
Code by grouping node kinds into accessible color-and-shape families,
coloring edges by relationship purpose while retaining confidence strokes,
Expand Down
8 changes: 8 additions & 0 deletions COMPATIBILITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,14 @@ product checkout.

## Evolving contracts

Swift, Dart, Scala, and Groovy/Gradle now publish through their version-1
universal evidence pipelines. The four pipelines are intentionally
`Qualifying`: they use one bounded, source-grounded publication route and may
change unresolved/ambiguous edges compared with older direct extraction. Normal
cache fingerprints invalidate affected files; users do not need to delete
artifacts manually. Equal names across Swift/native or JVM-family languages do
not by themselves create cross-language targets.

A user-visible incompatible change requires:

1. native regression coverage;
Expand Down
851 changes: 851 additions & 0 deletions advisor-plans/020-swift-dart-scala-groovy-universal.md

Large diffs are not rendered by default.

24 changes: 24 additions & 0 deletions advisor-plans/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,23 @@ quality gates. The pinned three-corpus audit now passes (89,981 accepted
relationships, 100% observed precision, 98.5567% recall); Ruby remains
`Qualifying` until a separate promotion decision.

Plan 020 is the Swift, Dart, Scala, and Groovy universal-evidence program. It
was planned at Compass commit `88abe4c0` on 2026-08-21. All four languages are
already recognized and have established extraction, so the program freezes
that behavior, builds independent source oracles and qualification-only
candidates, performs one atomic hard cut per language, preserves existing
Vapor/Dart/Play/Spock/Gradle behavior through evidence-backed boundaries, and
finishes with a mixed-language release gate. Swift, Dart, and Scala candidates
can proceed independently after the shared baseline; Groovy reuses Scala's
exact-language JVM boundary.
The production hard cut, deterministic fixture baselines, pinned manifests,
parser-backed source-oracle providers, audit builder, mixed fixture gate, and
three-corpus quality audits are implemented. The plan is `DONE`; all four
registry entries intentionally remain version-1 `Qualifying` until a separate
promotion decision. The mounted qualification target records the pinned
SwiftSyntax, Dart Analyzer, scala.meta, and Groovy CompilationUnit toolchains
and the immutable audit results.

## Execution order and status

| Plan | Title | Priority | Effort | Depends on | Status |
Expand All @@ -66,6 +83,7 @@ relationships, 100% observed precision, 98.5567% recall); Ruby remains
| 017 | Derive bounded, ranked execution flows from entry points | P2 | L | Existing universal call graph | TODO |
| 018 | Expose five native MCP workflow prompts | P2 | M | — | TODO |
| 019 | Hard-cut Ruby to a qualifying universal evidence pipeline | P1 | XL | —; final gate should consume 005 or equivalent | IN PROGRESS |
| 020 | Hard-cut Swift, Dart, Scala, and Groovy to universal evidence | P1 | XXL | —; final gate should consume 005 or equivalent | DONE |

Status values: `TODO`, `IN PROGRESS`, `DONE`, `BLOCKED`, or `REJECTED`.

Expand Down Expand Up @@ -106,6 +124,12 @@ Status values: `TODO`, `IN PROGRESS`, `DONE`, `BLOCKED`, or `REJECTED`.
Rails pack stay qualification-only until one atomic production hard cut;
optimization follows semantic parity; and complete promotion remains gated
by the 2,000-record quality audit.
- Plan 020 is one program with four independent language tracks. Phase 0
freezes shared baselines and independent truth. Swift, Dart, and Scala
candidates may then proceed in parallel; Groovy may also proceed but must
reuse the exact-language JVM boundary established for Scala. Each language
has a separate candidate and atomic hard-cut phase, and the mixed-language
release gate runs only after all four cuts.

## Direction options not promoted to implementation plans

Expand Down
48 changes: 45 additions & 3 deletions benchmarks/performance/compass/audit.py
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,8 @@ def _source_oracle_candidates(
corpus_commit: str,
producer: str,
compass_nodes: dict[str, Any],
include_globs: tuple[str, ...] = (),
exclude_globs: tuple[str, ...] = (),
) -> tuple[list[dict[str, Any]], dict[str, Any]]:
"""Export independently parsed source constructs for recall adjudication."""

Expand All @@ -346,7 +348,12 @@ def _source_oracle_candidates(
if node.qualified_name:
owners[node.qualified_name.casefold()].append(identifier)

inventory = independent_source_inventory(corpus_root, producer)
inventory = independent_source_inventory(
corpus_root,
producer,
include_globs=include_globs,
exclude_globs=exclude_globs,
)
candidates: list[dict[str, Any]] = []
for construct in inventory.constructs:
bounded = source_index.exact_range(
Expand Down Expand Up @@ -731,14 +738,27 @@ def _corpus(value: object, index: int) -> AuditCorpus:
_keys(
item,
required=("name", "commit", "path", "graph", "graphSha256"),
optional=("sourceGlobs", "excludeGlobs"),
context=context,
)
source_globs = item.get("sourceGlobs", [])
exclude_globs = item.get("excludeGlobs", [])
if not isinstance(source_globs, list) or any(
not isinstance(pattern, str) or not pattern for pattern in source_globs
):
raise AuditError(f"{context}.sourceGlobs must be a list of non-empty strings")
if not isinstance(exclude_globs, list) or any(
not isinstance(pattern, str) or not pattern for pattern in exclude_globs
):
raise AuditError(f"{context}.excludeGlobs must be a list of non-empty strings")
return AuditCorpus(
name=_text(item["name"], f"{context}.name", identity=True),
commit=_commit(item["commit"], f"{context}.commit"),
path=_safe_path(item["path"], f"{context}.path", allow_dot=True),
graph=_safe_path(item["graph"], f"{context}.graph"),
graph_sha256=_sha256(item["graphSha256"], f"{context}.graphSha256"),
source_globs=tuple(source_globs),
exclude_globs=tuple(exclude_globs),
)


Expand Down Expand Up @@ -1161,6 +1181,7 @@ def _validate_record_inputs(
) -> dict[str, _GraphIndex]:
indexes: dict[str, _GraphIndex] = {}
corpus_roots: dict[str, Path] = {}
corpus_specs = {corpus.name: corpus for corpus in manifest.corpora}
single = len(manifest.corpora) == 1
for corpus in manifest.corpora:
root = corpus_root if single and corpus.path == "." else corpus_root / corpus.path
Expand Down Expand Up @@ -1197,7 +1218,13 @@ def _validate_record_inputs(
f"provider mismatch: expected {source_oracle.provider!r}, "
f"observed {provider!r}"
)
inventory = independent_source_inventory(root, source_oracle.producer)
corpus = corpus_specs[source_oracle.corpus]
inventory = independent_source_inventory(
root,
source_oracle.producer,
include_globs=corpus.source_globs,
exclude_globs=corpus.exclude_globs,
)
observed_counts = (inventory.scanned_files, inventory.parsed_files)
expected_counts = (
source_oracle.scanned_files,
Expand All @@ -1218,6 +1245,17 @@ def _validate_record_inputs(
"inventory digest mismatch: "
f"expected {source_oracle.inventory_sha256}, observed {observed_digest}"
)
metadata = dict(inventory.provider_metadata)
# Legacy providers (for example the built-in Python AST oracle) do
# not publish parser metadata and remain governed by their existing
# contracts. The universal-language wrappers explicitly publish
# ``oracleImplementation``/``parserAvailable`` so a bounded lexical
# fallback cannot be mistaken for a promotion-grade parser oracle.
if metadata.get("oracleImplementation") and metadata.get("parserAvailable") != "true":
raise AuditError(
f"source oracle {(source_oracle.corpus, source_oracle.producer)!r} "
"is a reproducible fallback inventory, not a pinned parser provider"
)

for record in manifest.records:
root = corpus_roots[record.corpus]
Expand Down Expand Up @@ -1245,7 +1283,11 @@ def _validate_record_inputs(
)

graph = indexes[record.corpus]
if record.source.node_id not in graph.nodes:
requires_source_node = not (
record.pool == "source_oracle"
and record.judgment in {"missing", "ambiguous"}
)
if requires_source_node and record.source.node_id not in graph.nodes:
raise AuditError(
f"record {record.record_id!r} source node is absent from the graph"
)
Expand Down
2 changes: 2 additions & 0 deletions benchmarks/performance/compass/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,8 @@ class AuditCorpus:
path: str
graph: str
graph_sha256: str
source_globs: tuple[str, ...] = ()
exclude_globs: tuple[str, ...] = ()


@dataclass(frozen=True)
Expand Down
Loading
Loading