Skip to content

fix(config): complete project language overrides - #10

Merged
andrebrait merged 3 commits into
issue/3275-refresh-graphify-0-9-59-andfrom
issue/3275-graphify-reviewed-integration
Sep 12, 2026
Merged

fix(config): complete project language overrides#10
andrebrait merged 3 commits into
issue/3275-refresh-graphify-0-9-59-andfrom
issue/3275-graphify-reviewed-integration

Conversation

@andrebrait

@andrebrait andrebrait commented Sep 12, 2026

Copy link
Copy Markdown
Member

Summary

Complete the project-language override integration from Graphify-Labs#3075 on top of upstream 0.9.59. This PR targets the maintained fork branch, preserving the upstream-tracking v8 branch and all existing tags.

  • Apply declared languages inside extractors and cross-file passes, including TypeScript grammar/cache behavior and Python/Java/Go/C# resolution.
  • Resolve declared JS/Python module suffixes and package initializers without changing native precedence, physical source paths, or Python 3 import scope.
  • Invalidate incremental manifests when language declarations change and handle configuration/source events correctly in the watcher, including relative roots, atomic replacement, and semantic-work notifications.
  • Preserve the existing fork's suffix validation and interpreter-gated Leiden packaging.

Verification

Current head: a59563e5c0f63d6a71eaf7df6c4c97ae30564098. The initial changes were independently reviewed at 481574300794093d44ea40d5371db0ef058b21fa; the final commit applies the received Copilot corrections with frozen regressions.

  • Full fork suite: 5,720 passed, 14 skipped (existing platform/service-dependent skips).
  • Focused regression suite: 124 passed. The initial 99 tests were independently replayed: 39 failed, 60 passed on 9be01cc. Copilot regressions ran 10 failed / 13 passed, plus 2 failed watcher cases before their fixes; the same frozen tests now pass.
  • Independent integration gate: 22 additional probes passed, 11 fault mutations detected; no remaining blockers.
  • Separate condensed contract/correctness/test-honesty/simplicity review: PASS, with independent red/green and hostile-input replays.
  • uv lock --check, Ruff, wheel and source-distribution builds passed. Built production bytes match the reviewed source.
  • Real CLI incremental extraction and live watcher processes verified, including default/relative roots and clean shutdown.
  • Installed fork provenance verified on Python 3.13.5; native Leiden 1.3.1 successfully partitioned the runtime probe.

Chronological regression evidence and the integration history are recorded in pfBlockerNG/pfBlockerNG#3275. No test assertions were weakened; fixture-only maintenance is explicitly separated from production red/green proof.

Refs pfBlockerNG/pfBlockerNG#3275.

External review disposition

All seven Copilot findings were validated and addressed in the final commit; see the resolution audit and inline reply. CodeRabbit was requested twice and remained unavailable (not reported as a clean review).

@andrebrait

Copy link
Copy Markdown
Member Author

Independent review and integration gate

Reviewed head: 481574300794093d44ea40d5371db0ef058b21fa (base 9be01cc).

The condensed contract, correctness/hostile-input, test-honesty, and simplicity review passed with no findings remaining. Review invocation: OMP reviewer, anthropic/claude-sonnet-5, requested effort hi. A separate integration verifier independently replayed the regression and mutation evidence.

  • Full local suite: 5,695 passed, 14 skipped; skips are documented platform/service cases, not claimed coverage.
  • Final focused suite: 99 passed; immutable-baseline replay: 39 failed, 60 passed.
  • Independent probes: 22 passed; 11 fault mutations detected.
  • Real graphify watch processes for . and src rebuilt graphs, preserved relative source identity, signalled semantic work, and exited cleanly.
  • Lock, Ruff, wheel and source-distribution checks passed; built production bytes match the reviewed files.
  • Test assertions were not weakened. The recursive no_cluster test-wrapper repair and event-driver extensions are fixture maintenance, not mislabeled production red/green proof. Earlier fix-first drafts were discarded; the accepted integration began with a clean baseline and recorded RED tests.

Per-file disposition

File Verdict
README.md PASS — new prose accurately reflects verified behavior: manifest invalidation on declaration change, watch root-config/atomic-replacement handling, JS/Python suffix fallback with native precedence, Fortran/C-header exclusions.
graphify/detect.py PASS — save_manifest re-activates the given root's overrides before hashing (fixes cross-thread staleness); language-change detection (lang_changed) correctly invalidates ast/semantic tiers independently, handles legacy scalar/dict/tiers rows via prev.get('language') defaulting to None, and never tags never-declared files with a 'language' key (legacy-compatible).
graphify/extract.py PASS — every dispatch/eligibility/cache-bypass site (_extract_single_file, _extract_sequential, extract, Java/Go/C#/Python cross-file selectors) consistently swapped .suffix for effective_suffix; Python package/sibling repoint passes use the new shared _is_python_package_dir helper with correct default/explicit suffix sets, preserving PEP 328 implicit-relative guard.
graphify/extractors/csharp.py PASS — _is_cs_file/_is_dotnet_source_file now suffix-aware; extraction to a shared predicate is a genuine DRY improvement with no behavior change for native .cs (case-sensitivity preserved).
graphify/extractors/ocaml.py PASS — single-line effective_suffix swap for .mli grammar selection; verified via existing mutation-killed test.
graphify/extractors/resolution.py PASS — largest and highest-risk file; _declared_language_suffixes traversal guard independently verified (see probes above); native-before-declared ordering preserved for both JS file/index resolution and Python module/package resolution; G2/G3/G4 fixes all independently re-verified, not just re-read from logs.
graphify/extractors/robot.py PASS — .resource grammar selection now suffix-aware; consistent with mutation-killed coverage.
graphify/symbol_resolution.py PASS — Python-caller eligibility gates now suffix-aware in both collection passes.
graphify/watch.py PASS — thread-local override snapshot correctly re-seeded on both observer and dispatch threads before any effective_suffix-dependent decision; G1 fix (observer registered on absolute watch_root_for_ignore) verified to keep _rebuild_code(watch_path) on the original — possibly relative — argument, preserving relative source_file identity in the graph, matching gate's real watcher proof (page.tpl / src/page.tpl) and the mocked relative-root test.
tests/test_language_overrides.py PASS — original 409 lines byte-identical to base (blob 09d3d1d... unchanged across initial/final gate hashes); append-only new regression cases.
tests/test_language_override_lifecycle.py PASS — new file; assertions are genuine (manifest invalidation, thread-mapped observer/dispatch snapshot, ignored/read-only guards, semantic-flag visibility, relative-root source-path preservation); the reported 'duplicate no_cluster' correction is pure test-harness fixture code (forces no_cluster=True on every rebuild call for test speed) with zero bearing on the production contract under test — correctly test maintenance, not mislabeled production work.
tests/test_language_override_imports.py PASS — new file; each test fails on the immutable base (independently re-confirmed) and passes on HEAD; includes the traversal-safety regression test I independently reproduced against a second attack surface (Python) not covered by the file's own JS-only traversal test.

No blocking or optional findings remain. Exact-head CI and external review are the remaining landing gates.

@andrebrait

Copy link
Copy Markdown
Member Author

@coderabbitai review

@andrebrait

Copy link
Copy Markdown
Member Author

@coderabbitai review

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Seven unresolved moderate findings affect override-aware passes, resolution, call-scope handling, and ignored .graphifyrc events.

Get a fresh assessment by requesting another Copilot review.

Pull request overview

Completes project-language override support across extraction, resolution, incremental manifests, and watcher lifecycle.

Changes:

  • Applies declared suffixes to extractors and JS/Python resolution.
  • Invalidates manifests and handles configuration/source watcher events.
  • Adds documentation and regression coverage.
File summaries
File Summary Review status
tests/test_language_overrides.py Tests extractor and cross-file integration. No final comments.
tests/test_language_override_lifecycle.py Tests manifests and watcher lifecycle. No final comments.
tests/test_language_override_imports.py Tests declared module and package imports. No final comments.
README.md Documents override and lifecycle behavior. No final comments.
graphify/watch.py Handles configuration and source events. Moderate (1 vote): process root .graphifyrc events before ignore filtering.
graphify/symbol_resolution.py Includes declared Python files in symbol resolution. No final comments.
graphify/extractors/robot.py Supports declared Robot resource suffixes. No final comments.
graphify/extractors/resolution.py Resolves declared JS/Python modules and packages. Four moderate findings (1 vote each): gate native candidates, package initializers, module paths, and call-scope checks with effective suffixes.
graphify/extractors/ocaml.py Selects OCaml parsing by effective suffix. No final comments.
graphify/extractors/csharp.py Applies overrides to C# detection. Moderate (1 vote): propagate effective suffixes through partial, inherited, and dispatch checks.
graphify/extract.py Applies overrides during extraction and cross-file passes. Moderate (2 votes): replace remaining raw .cs checks in partial merging and base-chain filtering.
graphify/detect.py Tracks overrides in incremental manifests. No final comments.
Review details

Suppressed comments (6)

graphify/extractors/csharp.py:153

  • Making _is_cs_file() override-aware does not reach all downstream C# consumers. extract.py still filters partial-class nodes and inherited-base edges by physical .cs, while csharp_dispatch.py uses the same raw suffix for both its activation guard and node checks. With language.rzr=csharp, partial types stay split, inherited member calls cannot walk their bases, and interface dispatch exits without adding edges. Propagate the effective-suffix predicate through these passes and add regressions for the declared suffix.
def _is_cs_file(value: object) -> bool:
    return isinstance(value, str) and effective_suffix(value) == ".cs"

graphify/extractors/resolution.py:74

  • The native candidate loop checks raw suffixes only, so it can return a file that the override has explicitly changed to another language. For example, with language.ts=php and language.tpl=typescript, an extensionless ./dep resolves to dep.ts here even though that file is no longer JS; the native directory-index loop below has the same problem. Filter native candidates/indexes through effective_suffix before returning so native precedence is preserved only among JS files.
    for ext in _JS_RESOLVE_EXTS + declared_exts:
        with_ext = candidate.parent / f"{candidate.name}{ext}"
        if with_ext.is_file():
            return with_ext

graphify/extractors/resolution.py:2088

  • This package-scope check ignores overrides on the native Python suffix. With language.py=javascript (or another non-Python target), __init__.py is not a Python initializer, but this still marks its directory as a Python package and suppresses the sys.path-root walk. Check the initializer with effective_suffix before treating it as a Python package.
    if any((directory / f"__init__{suffix}").is_file() for suffix in suffixes):

graphify/extractors/resolution.py:2115

  • The native package probe (and the .py module probe immediately below it) returns raw .py paths without checking whether the project remapped .py away from Python. Thus a Python file using a declared suffix can bind to a non-Python dep.py or dep/__init__.py, contrary to the override contract and the intended native-precedence rule. Gate both native returns with effective_suffix(...) == ".py" before falling back to declared Python suffixes.
    if candidate.is_dir():
        init_path = candidate / "__init__.py"
        if init_path.is_file():
            return init_path
    if candidate.is_file():

graphify/extractors/resolution.py:1802

  • By including remapped files in the JS symbol-resolution path here, the PR also sends them through the generic cross-file call pipeline, but that pipeline's no-implicit-scope guard in extract.py still checks rc.source_file.endswith(_JS_TS_CALL_SUFFIXES) against the physical suffix. A language.tpl=typescript caller therefore bypasses the guard and can bind an unimported call to a lone same-named export, unlike a native .ts caller. Use effective_suffix for that raw-call gate and add a declared-suffix no-import regression.
def _collect_js_symbol_resolution_facts(paths: list[Path], facts: _SymbolResolutionFacts) -> None:
    js_paths = [
        path for path in paths
        if effective_suffix(path) in _JS_CACHE_BYPASS_SUFFIXES
    ]

graphify/watch.py:2238

  • The watcher applies _is_ignored before checking the root .graphifyrc, so an ignore pattern such as .graphifyrc or .* causes config modify/delete events—and atomic moves whose destination is .graphifyrc—to return here. The old override snapshot then remains active and no rebuild is scheduled. Check the root config (including dest_path) before the ignore filter.
            if ignore_patterns and _is_ignored(path, watch_root_for_ignore, ignore_patterns):
  • Files reviewed: 12/12 changed files
  • Comments generated: 1
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread graphify/extract.py
Comment on lines 7201 to +7204
_DOTNET_TYPE_EXTS = {".cs", ".razor", ".cshtml"}
cs_paths = [p for p in paths if p.suffix.lower() in _DOTNET_TYPE_EXTS]
cs_paths = [p for p in paths if effective_suffix(p).lower() in _DOTNET_TYPE_EXTS]
if cs_paths:
cs_results = [r for r, p in zip(per_file, paths) if p.suffix.lower() in _DOTNET_TYPE_EXTS]
cs_results = [r for r, p in zip(per_file, paths) if effective_suffix(p).lower() in _DOTNET_TYPE_EXTS]

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Applied in a59563e. Shared C# predicates now cover partial merging, inherited-member base chains, scoped rewiring and interface dispatch. Native/declared regressions failed before the fix and pass unchanged afterward; full suite: 5,720 passed, 14 existing skips.

@andrebrait

Copy link
Copy Markdown
Member Author

Applied in a59563e5c0f63d6a71eaf7df6c4c97ae30564098.

Received finding Resolution
C# partial/inherited passes Reused effective-language C# predicates in partial merging, inherited-base filtering and scoped stub rewiring.
C# interface dispatch Reused the same predicate for corpus and endpoint eligibility.
Native JS candidates remapped away Native file, index and ESM-substitution candidates must still be JS-family; declared alternatives retain their fallback role.
Native Python package markers remapped away Package markers must retain an effective Python suffix.
Native Python module/package candidates remapped away Native .py candidates are checked before returning; valid declared Python alternatives remain available.
JS no-implicit-call scope Declared JS/TS callers now pass through the existing import-evidence guard.
Ignored root configuration Root .graphifyrc control events, including atomic replacement, are handled before corpus ignore filtering. Other ignore/read-only/output guards remain unchanged.

Targeted tests ran before production edits: 10 failed / 13 passed, plus 2 failed watcher cases. The same frozen tests now pass; the combined focused set is 124 passed. Full suite: 5,720 passed / 14 existing skips. Ruff, lock and package builds passed.

These are the review's concrete corrections, not a new investigation or feature pass. Per the concrete-suggestion fix-round exception, no additional broad adversarial round was opened. Exact-head CI is being rerun.

CodeRabbit was requested twice on this fork PR and produced no response. This is recorded as unavailable, not a clean review; the missed-review ledger will reference the landed SHA.

@andrebrait
andrebrait merged commit a59563e into issue/3275-refresh-graphify-0-9-59-and Sep 12, 2026
4 checks passed
@andrebrait

Copy link
Copy Markdown
Member Author

Landed by signed fast-forward of the maintained fork branch at a59563e5c0f63d6a71eaf7df6c4c97ae30564098; post-push PR head fence and ancestry checks passed. GitHub reports this PR MERGED. Signed tag v0.9.59-pfb.1 resolves to that exact commit. Exact-head CI is green on Python 3.10/3.12, skill-generation and security jobs. All Copilot findings were addressed; CodeRabbit was silent after both permitted requests. Existing tags and the upstream-tracking branch were not rewritten.

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.

2 participants