brick/docs/research/language-correctness.md
trvon 46698cd87d
Some checks failed
build / build-linux (pull_request) Successful in 1m3s
build / build-macos (pull_request) Has been cancelled
build / release (pull_request) Has been cancelled
docs: state resolution rules and limits as the code now implements them
The audit found README claims the code did not back: resolution was said
to respect lexical namespace everywhere (Python/Swift matched a
repo-wide unique name, Rust types their leaf name), "ambiguous targets
stay external" (not for rival using-directives or #else stubs), Dart
imports were said to resolve (no Dart symbol ever did across files), and
"C/C++" hid that C went through the C++ grammar.

The README now describes the fixed behaviour and its remaining limits:
per-language visibility rules (Python imports, Swift module-wide names,
Dart imported libraries without show/hide), Rust type identity by
declaring file, preprocessor alternatives excluded from resolution,
using-directive ambiguity, the C grammar for .c, Fold report
validation and producer-gated symbolic lane, lossy UTF-8 decoding,
diagnostic counts and empty-scan reporting, check recomputing metrics,
low call-site coverage on large C++ code, no virtual-override fan-out,
and unrecognized Catch2 TEST_CASE bodies. The research note lists the
pinned C grammar.
2026-09-24 20:21:29 -06:00

108 lines
6.3 KiB
Markdown

# Language correctness work
The attached September 4 review is the acceptance scope: source-relative imports,
language/scoped resolution, comment and string exclusion, symlink containment,
C++ inline functions/constructors, JS arrows/default exports/methods, TS interfaces
and generics, Dart multiline methods, Rust const functions and impl ownership,
and Fold absolute path aliases. Each item needs positive and clean-negative
public-model tests and a passing quality gate under the default environment.
Experiment contract:
```json
{
"hypothesis": "Grammar-based source extraction and scoped resolution remove the reported false edges and recover missing declarations and owners",
"owner": "source extractor and resolver; separate filesystem and Fold path fixes",
"fixtures": ["tests/languages.rs", "tests/fixtures/languages"],
"expected": {
"increases": ["labeled declaration recall", "labeled dependency precision and recall"],
"preserves": ["unrelated stable IDs", "schema 4 JSON contract", "heuristic resolution confidence", "P4 and imported evidence lanes"]
},
"decision": "promote the covered default syntax extractor; retain heuristic resolution and explicit limits"
}
```
Declaration ownership fixes intentionally change identities for previously
misowned methods. Removal of false edges and recovery of real functions can
change cycle, isolation, and fan metrics; no health weights are changed.
## Acceptance evidence
`tests/languages.rs` exercises every attached concern through the public scanner:
| Concern | Regression evidence |
| --- | --- |
| Wrong relative imports | Existing local JS/TS/Dart paths resolve despite duplicate basenames; C++ parent-relative includes resolve; missing paths stay external |
| Cross-language/scoped false edges | Same-file language/owner lookup, namespace separation, explicit imported aliases, parameter shadowing, private/type-only negatives |
| Comments and strings | Clean-negative C++ raw strings, JS templates, TS URL strings, Dart triple strings, Rust raw strings |
| Symlink escape | Outside directory/file links, internal aliases, and cycles are skipped with relative diagnostics |
| C++ inline functions/constructors | Exact constructor/method parents and three body calls; no declaration-name calls |
| JS and TS syntax | Arrows, default exports, methods, interfaces, generics, and TSX expression bodies |
| Dart multiline method | Method has class parent and owns its helper call |
| Rust const/impl | Const function, distinct type-owned methods, stable IDs after unrelated insertions; unresolved impl cannot create cyclic ownership |
| Fold absolute alias | `src/fold.rs` tests existing root aliases while rejecting outside and excluded files; original default-tempdir test passes |
The grammar versions are pinned in Cargo.toml and Cargo.lock: C 0.24.2 (`.c`
files), C++ 0.23.4,
JavaScript 0.25.0, TypeScript/TSX 0.23.2, Dart 0.2.0, Rust 0.24.2, with the
Tree-sitter Rust runtime at 0.26.13. Upstream API/grammar references:
[C++](https://docs.rs/tree-sitter-cpp/0.23.4/tree_sitter_cpp/),
[TypeScript](https://docs.rs/tree-sitter-typescript/0.23.2/tree_sitter_typescript/),
[Dart](https://github.com/nielsenko/tree-sitter-dart).
Building these grammar crates requires a C compiler in addition to pinned Rust.
## Repeated baseline/candidate experiment
`tests/fixtures/languages/labels.json` is authored independently of scanner output.
It enumerates 33 symbols with ownership and 12 dependency relationships across
13 files, stratified as C++, JS, TS, TSX, Dart, and Rust. Every emitted declaration
and dependency participates in exact comparison, including clean negatives.
The original HEAD was archived and built separately under
`build/language-baseline-src` / `build/language-baseline-target`. Three baseline
scans and three candidate scans use the same absolute corpus root:
| Targeted corpus result | Original extractor | Candidate |
| --- | ---: | ---: |
| Correct symbols | 16 / 33 | 33 / 33 |
| Missing symbols | 17 | 0 |
| Correct dependencies | 1 / 12 | 12 / 12 |
| Unexpected dependencies | 29 | 0 |
| Missing dependencies | 11 | 0 |
| Full JSON stable over three repeats | yes | yes |
Raw baseline JSON/HTML, archived-source hash, executable hash, corpus provenance,
resolved plan, and results live under `build/benchmarks/source_languages/baseline`.
Candidate runs live in timestamped directories under
`build/benchmarks/source_languages`; the quality gate writes a fresh three-repeat
run with Git working-tree fingerprint, raw models, command logs, latency, and RSS.
These are targeted regression results, not language-wide precision or performance
claims. The retained lexical_smoke benchmark also passes after the changes.
The policy integration fixture now uses the explicit Rust path
`crate::storage::db::query()` and a public target. Its former unqualified reference
between unrelated files depended on the global-name bug. The gate still verifies
one real forbidden dependency, and MCP/policy evidence tests expect the new
grammar-plus-heuristic backend string without weakening lane/confidence checks.
## Remaining scope boundaries
No compiler type checking, macro expansion, generated-source discovery, dynamic
dispatch, overload resolution, or full build/package configuration is claimed.
Member calls remain unresolved without receiver evidence. Package specifiers,
tsconfig aliases, Rust grouped-use bindings, and C++ cross-translation-unit
resolution still need adapters. Anonymous callbacks without a declaration name
are attributed to the enclosing named function. These limits are documented
rather than silently converting uncertain targets into known dependencies.
Schema 4 needs no new reader behavior: the same graph/evidence contract carries
the new facts and optional attributes. Corrected owners and scoped unknowns have
intentional identity changes; unrelated simple declarations retain their IDs.
P4 stays on its existing independent frontend and evidence paths.
Validation commands: `cargo fmt --check`, `cargo test`,
`cargo clippy --all-targets -- -D warnings`, `./scripts/quality-gate.sh`, and
`python3 tests/benchmarks/runner.py self-test`. The quality gate includes optional
P4 tests/lint, Python harness tests, the three-repeat source plan, and existing
diff/policy/MCP harness self-tests. Use the default environment; no TMPDIR
workaround is required. The final log is `build/language-quality-gate.log`.