Skip to content

feat(parity): port the JS points-to solver to native and unify engine resolution#1465

Merged
carlos-alm merged 6 commits into
mainfrom
refactor/engine-structure-parity
Jun 12, 2026
Merged

feat(parity): port the JS points-to solver to native and unify engine resolution#1465
carlos-alm merged 6 commits into
mainfrom
refactor/engine-structure-parity

Conversation

@carlos-alm

Copy link
Copy Markdown
Contributor

Summary

Brings the native (Rust) and WASM (TS) engines to full resolution parity on the JavaScript fixture set, taking the best of both implementations rather than restricting changes to one language. Stacked on #1463 (mirrored module layout).

Native (Rust) — JS→native port:

  • The JS extractor now collects all eight points-to binding kinds (param, this-call, array-element, spread-arg, for-of, array-callback, object-rest-param, object-prop) and surfaces them on FileSymbols.
  • build_call_edges runs the same fixed-point points-to solver as the WASM path: thisCall→fnRef conversion, the four-case key gate with receiver-key fallback, and hop-penalised alias edges with the pts upgrade mechanism.
  • Inline-new receivers are normalized (new A().t() → receiver "A") in extract_receiver_name, mirroring extractReceiverName in the TS extractor.
  • Exact cross-file lookups apply the ≥0.5 confidence filter WASM uses.

WASM/TS — native→JS backport and cleanup:

  • NativeFileEntry plumbs params and the eight binding arrays so the hybrid path feeds the native solver; thisCallBindings is serialized across the WASM worker boundary.
  • The native engine's class-field type-annotation extraction is backported (private repo: Repository seeds typeMap repo/this.repo).
  • The four JS pts post-passes that duplicated the native solver on the hybrid path are removed (~360 lines) — single source of truth for pts resolution per path.
  • The native build summary and build_meta counts are now reported after the JS edge-writing post-passes, so they include CHA/this-dispatch edges.

Verification

  • WASM, full-native orchestrator, and hybrid builds produce identical edge multisets on the javascript fixture — 155 rows each, compared including confidence and dynamic flags.
  • javascript fixture: 42/42 expected edges on both engines (was native 36/42, bug: native engine misses 6 expected call edges in JavaScript fixture (85% vs WASM 100% recall) #1453); pts-javascript: 13/13 on both (was native 3/13).
  • 392 Rust tests (22 new), 3043 JS tests, and the 176-test resolution benchmark across all 34 language fixtures are green.

Closes #1453
Closes #1452
Closes #1439

Test plan

  • cargo test — 392 passed
  • Full vitest suite — 3043 passed
  • Resolution benchmark (all languages) — 176 passed
  • Engine edge-multiset diff (wasm vs native vs hybrid) — zero divergence

Reorganize crates/codegraph-core/src/ so every module sits at the path of
its TypeScript counterpart (snake_case for kebab-case): shared/,
infrastructure/, db/repository/, domain/graph/builder/stages/,
ast_analysis/, graph/algorithms/, graph/classifiers/, features/.

- Pure git mv moves; only graph_algorithms.rs is split (bfs, shortest_path,
  centrality, louvain) along its existing section boundaries
- lib.rs doc comment carries the full Rust<->TypeScript mapping table
- Cross-references in TS sources, tests, and docs updated to new paths
- Cargo.lock version synced to 3.12.0 (Cargo.toml was already bumped)
- cargo test: 360 passed; tsc build and drift-guard test green
…nify per-engine resolution

Native (Rust):
- Extract all eight pts binding kinds in the JS extractor (param,
  this-call, array-element, spread-arg, for-of, array-callback,
  object-rest-param, object-prop) and surface them on FileSymbols
- Run the same fixed-point points-to solver as the WASM path inside
  build_call_edges: thisCall-to-fnRef conversion, four-case key gate with
  receiver-key fallback, hop-penalised alias edges with pts upgrade
- Normalize inline-new receivers (new A().t() -> receiver "A") in
  extract_receiver_name, mirroring extractReceiverName in the TS extractor
- Apply the >=0.5 confidence filter on exact cross-file lookups (#1439)

WASM/TS:
- Plumb params and all eight binding arrays through NativeFileEntry so the
  hybrid path feeds the native solver
- Serialize thisCallBindings across the WASM worker boundary
- Backport the native engine's class-field type-annotation extraction
  (private repo: Repository seeds typeMap "repo"/"this.repo")
- Remove the four JS pts post-passes that duplicated the native solver on
  the hybrid path (param-flow, fnRef, thisCall, object-rest)
- Report the native build summary and build_meta counts after the JS
  edge-writing post-passes so they include CHA/this-dispatch edges (#1452)

WASM, full-native orchestrator, and hybrid builds now produce identical
edge multisets on the javascript fixture (155 rows each, including
confidence and dynamic flags); javascript 42/42 and pts-javascript 13/13
expected edges on both engines; 392 Rust tests, 3043 JS tests, and the
176-test resolution benchmark are green.

Closes #1453
Closes #1452
Closes #1439
@claude

claude Bot commented Jun 12, 2026

Copy link
Copy Markdown

Claude finished @carlos-alm's task —— View job


PR Review: feat(parity): port the JS points-to solver to native and unify engine resolution


Root Cause Analysis

Problem Being Solved: Native (Rust) engine resolved only 36/42 expected JS edges and 3/13 pts-javascript edges (#1453), while WASM resolved 42/42 and 13/13. The root cause was two-fold: (1) the JS extractor never surfaced its eight pts binding kinds to FileSymbols, so the Rust build_call_edges received no pts inputs and ran a stub solver; and (2) the WASM/hybrid path had four JS post-passes duplicating the native solver after it had already been ported.

Why This Approach: The PR takes the correct architectural approach — fix the root cause (missing pts extraction + missing solver) rather than hiding the discrepancy. It ports the full fixed-point pts solver from TS to Rust, backports a class-field type-annotation extraction gap to TS, removes the now-redundant JS post-passes, and ensures the WASM worker serializes thisCallBindings across the boundary. This is a legitimate parity fix, not symptom masking.

Risk Assessment: Medium. The change is large (2150 additions) but focused on a single subsystem (pts resolution). The PR claims identical edge multisets across all three paths with 3043 passing JS tests + 392 Rust tests + 176-benchmark green. The duplicate-builtin-globals list and a u32/usize mismatch in the Rust solver are the main correctness risks.


Phase 2: Configuration Change Detection

No linting rules, TypeScript flags, test timeouts, or coverage thresholds were modified. Clean.


Phase 3: Test Integrity

Test changes (tests/parsers/javascript.test.ts) add 11 new assertions covering thisCallBindings extraction — no assertions were weakened or removed, no tests skipped. Clean.


Phase 4: Code Quality Concerns

Bug: BUILTIN_GLOBALS divergence between TS and Rust

src/extractors/javascript.ts BUILTIN_GLOBALS includes process, window, document, globalThis (lines 89–93). The is_js_builtin_global function in crates/codegraph-core/src/extractors/javascript.rs also includes them (lines 247–249). However, the constant JS_BUILTIN_GLOBALS declared at the top of the same file (lines 10–21) omits process, window, document, and globalThis:

// javascript.rs:10–21 (JS_BUILTIN_GLOBALS — used for extracting calls)
const JS_BUILTIN_GLOBALS: &[&str] = &[
    "Math", "JSON", "Promise", "Array", ...
    "console", "Buffer", "EventEmitter", "Stream",
    // ← missing: process, window, document, globalThis
];
// javascript.rs:228–251 (is_js_builtin_global — used in type_map extraction)
fn is_js_builtin_global(name: &str) -> bool {
    matches!(
        name,
        ... | "console" | "process" | "window" | "document" | "globalThis"
        ...
    )
}

JS_BUILTIN_GLOBALS is used to filter call receiver names during extraction. is_js_builtin_global is used to guard obj.prop = identifier type-map seeding. The two sets should be identical but aren't — receiver-context builtins like process (e.g. process.env) will not be filtered as builtins during call extraction, potentially generating spurious call edges. This is a direct parity gap with the TS BUILTIN_GLOBALS set.

Reference: crates/codegraph-core/src/extractors/javascript.rs:10–21 vs 228–251.

Potential: u32 index for array_max_index may silently truncate on large arrays

In build_edges.rs:238:

let cur = array_max_index.entry(ab.array_name.as_str()).or_insert(-1);
if i64::from(ab.index) > *cur { *cur = i64::from(ab.index); }

ab.index is u32, cast to i64. This is safe. But at line 243:

for i in 0..=(max_idx as usize) {

If max_idx is -1 (no array elements found), max_idx as usize wraps to usize::MAX and the loop panics or runs 2^64 iterations. The guard if max_idx >= 0 on line 243 prevents this — the cast only fires inside the if. Not a bug, but worth a comment since the safety depends on that guard.

Minor: sort_targets_by_confidence called in native path but not in TS fallback

build_edges.rs:546–548:

let mut targets = resolve_call_targets(ctx, call, rel_path, imported_from, &type_map, caller_name);
sort_targets_by_confidence(&mut targets, rel_path, imported_from);
emit_call_edges(&targets, caller_id, ...);

The TS buildFileCallEdges in build-edges.ts iterates targets in the order returned by resolveCallTargets without sorting. This means confidence ranking could differ between engines when a call resolves to multiple targets with different confidences. If batchInsertEdges deduplicates on (source_id, target_id) with the first-inserted confidence, this is a latent parity difference for multi-file targets. Low risk since the tests pass, but it should be verified that the sort order never affects the dedup outcome.

Cosmetic: #[allow(clippy::too_many_arguments)] suppression

build_edges.rs:361 suppresses the lint for emit_pts_alias_edges, which takes 14 parameters. This is the right tradeoff for internal code mirroring the TS structure, but the arguments would benefit from a grouped parameter struct in a follow-up refactor (file an issue).

wasm-worker-pool.ts deserialization: thisCallBindings now plumbed through but not verified

wasm-worker-pool.ts now deserializes ser.thisCallBindings (added in this PR). The corresponding wasm-worker-entry.ts line adds thisCallBindings to the serialized output. Correct, but there is no test that verifies the worker boundary round-trips thisCallBindings intact — the new JS parser tests run against the extractor directly, not through the worker pool. If the worker boundary ever breaks serialization for this field, no test would catch it.

build-edges.ts:1610–1611: comment claims pts post-passes are removed, but buildDefinePropertyPostPass and buildChaPostPass remain

// The native engine receives all pts bindings … so no pts post-passes are needed here.
// Only capabilities that remain JS-only run as post-passes below.
buildDefinePropertyPostPass(ctx, getNodeIdStmt, allEdgeRows, sharedLookup);
buildChaPostPass(ctx, getNodeIdStmt, allEdgeRows, chaCtx);

The comment correctly distinguishes "pts post-passes" from "JS-only post-passes". This is accurate — the removed post-passes were objectRestParamPostPass, paramCallPostPass, etc. CHA and defineProperty remain JS-only. The comment is precise. Not an issue, just worth confirming.


Phase 5: Backlog Compliance

  • Zero-dep: ✓ — No new dependencies added. Builds on existing tree-sitter/SQLite/napi-rs.
  • Foundation-aligned: ✓ — Fully local, no cloud calls, no new toolchain requirements. Directly improves the core dependency graph's accuracy.
  • Problem-fit: 5 — Engine parity is foundational: a native engine that misses 17% of expected JS edges (36/42 → 42/42) would cause AI agents using the native path to miss blast radius and hallucinate absent call chains. Fixing this directly addresses the stated problem.
  • Breaking: No — additive pts binding fields on FileSymbols / NativeFileEntry are optional (?). No CLI output format, DB schema, or MCP contract changes.
  • Tier: 1 (zero-dep ✓ + foundation-aligned ✓)

Critical Concerns

  1. JS_BUILTIN_GLOBALS is missing process, window, document, globalThis compared to the TS BUILTIN_GLOBALS set and compared to the Rust is_js_builtin_global function in the same file. This creates an asymmetric builtin-receiver filter during call extraction — potentially generating spurious call edges from process.exit(), window.open(), etc. in the native extractor path, while the WASM path correctly suppresses them. This should be fixed before merge.

Final Recommendation

  • Rating: ⭐⭐⭐⭐ (4/5)
  • Action: APPROVE WITH CONDITIONS
  • Reasoning: This PR correctly fixes a real parity bug at the root cause, the approach is architecturally sound (ports the solver rather than papering over results), all tests are additive and meaningful, and the backlog compliance is Tier 1 / problem-fit 5. The single blocker is the JS_BUILTIN_GLOBALS incomplete constant (process/window/document/globalThis missing) which is a parity gap introduced by this PR in the native extractor. That and the sort_targets_by_confidence/multi-target dedup asymmetry are worth addressing; the rest are minor.

@github-actions

github-actions Bot commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Codegraph Impact Analysis

89 functions changed401 callers affected across 46 files

  • run_pipeline in crates/codegraph-core/src/domain/graph/builder/pipeline.rs:422 (0 transitive callers)
  • propagate_return_types_across_files in crates/codegraph-core/src/domain/graph/builder/pipeline.rs:1304 (4 transitive callers)
  • build_and_insert_call_edges in crates/codegraph-core/src/domain/graph/builder/pipeline.rs:1415 (1 transitive callers)
  • non_empty in crates/codegraph-core/src/domain/graph/builder/pipeline.rs:1456 (2 transitive callers)
  • make_import_ctx in crates/codegraph-core/src/domain/graph/builder/pipeline.rs:1929 (3 transitive callers)
  • entry in crates/codegraph-core/src/domain/graph/builder/pipeline.rs:1943 (5 transitive callers)
  • propagates_imported_factory_return_type_into_type_map in crates/codegraph-core/src/domain/graph/builder/pipeline.rs:1952 (0 transitive callers)
  • qualified_receiver_lookup_uses_global_return_type_map in crates/codegraph-core/src/domain/graph/builder/pipeline.rs:1987 (0 transitive callers)
  • locally_typed_variables_are_not_overwritten in crates/codegraph-core/src/domain/graph/builder/pipeline.rs:2013 (0 transitive callers)
  • build_points_to_map in crates/codegraph-core/src/domain/graph/builder/stages/build_edges.rs:192 (16 transitive callers)
  • emit_pts_alias_edges in crates/codegraph-core/src/domain/graph/builder/stages/build_edges.rs:367 (16 transitive callers)
  • process_file in crates/codegraph-core/src/domain/graph/builder/stages/build_edges.rs:435 (15 transitive callers)
  • resolve_call_targets in crates/codegraph-core/src/domain/graph/builder/stages/build_edges.rs:651 (17 transitive callers)
  • is_module_scoped_language in crates/codegraph-core/src/domain/graph/builder/stages/build_edges.rs:865 (4 transitive callers)
  • emit_receiver_edge in crates/codegraph-core/src/domain/graph/builder/stages/build_edges.rs:941 (16 transitive callers)
  • def in crates/codegraph-core/src/domain/graph/builder/stages/build_edges.rs:1655 (0 transitive callers)
  • make_file in crates/codegraph-core/src/domain/graph/builder/stages/build_edges.rs:1673 (6 transitive callers)
  • class_scoped_type_map_key_resolves_this_prop_receiver in crates/codegraph-core/src/domain/graph/builder/stages/build_edges.rs:1773 (0 transitive callers)
  • rest_param_scoped_type_map_key in crates/codegraph-core/src/domain/graph/builder/stages/build_edges.rs:1798 (0 transitive callers)
  • bare_call_in_js_skips_same_class_fallback in crates/codegraph-core/src/domain/graph/builder/stages/build_edges.rs:1822 (0 transitive callers)

@greptile-apps

greptile-apps Bot commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR brings the native Rust and WASM/TS engines to full JavaScript resolution parity by porting the complete points-to solver to Rust and eliminating the duplicated TS post-passes from the hybrid path. The result is a single source of truth for pts resolution per engine path, verified by identical 155-edge multisets across all three build modes.

  • Native engine (Rust): The JS extractor now collects all eight pts binding kinds; build_call_edges runs the same fixed-point solver, four-case key gate, thisCall→fnRef conversion, and hop-penalised alias edges with pts-upgrade as the WASM path. Phase 8.2 cross-file return-type propagation is added before call-edge building in pipeline.rs.
  • WASM/hybrid engine (TS): NativeFileEntry gains params and all eight binding arrays; thisCallBindings is now serialized across the worker boundary (fixing a silent data loss on the hybrid path). The four redundant JS pts post-passes (~360 lines) are removed.
  • Correctness gates passed: 42/42 JS fixture edges, 13/13 pts-javascript edges, 392 Rust tests, 3043 JS tests, and 176-test resolution benchmark all green.

Confidence Score: 5/5

Safe to merge — all three engine paths produce identical edge multisets on the JS fixture, and no regressions were found in the 3600+ test suite.

The algorithmic changes are thoroughly tested (392 Rust, 3043 JS, 176 benchmark), the removed TS post-passes are provably replaced by the native solver (zero edge-multiset divergence across all three build modes), and the thisCallBindings worker-boundary fix closes a previously silent data-loss path. No logic errors or missing invariants were identified in the pts solver, the fixed-point termination, or the pts-upgrade mechanism.

No files require special attention.

Important Files Changed

Filename Overview
crates/codegraph-core/src/domain/graph/builder/stages/build_edges.rs Full native pts solver port: adds fixed-point pts solver, four-case key gate, pts-upgrade mechanism, and hop-penalised alias edges; mirrors build-edges.ts faithfully.
crates/codegraph-core/src/domain/graph/builder/pipeline.rs Adds Phase 8.2 cross-file return-type propagation (propagate_return_types_across_files) before call-edge building; ties together the new native pts pipeline cleanly.
crates/codegraph-core/src/extractors/javascript.rs Adds all eight pts binding collectors (param, thisCall, arrayElem, spreadArg, forOf, arrayCallback, objectRestParam, objectProp) to the Rust JS extractor, bringing it to full parity with the TS extractor.
src/domain/graph/builder/stages/build-edges.ts Removes ~360 lines of hybrid-path pts post-passes that duplicated the native solver; wires thisCallBindings and all eight binding arrays into NativeFileEntry for the native edge builder.
src/domain/wasm-worker-protocol.ts Adds thisCallBindings to SerializedExtractorOutput so the binding survives the worker boundary and reaches the native solver on the hybrid path.
crates/codegraph-core/src/types.rs Adds all eight pts binding structs and TypeMapEntry with NAPI bindings; FileSymbols is extended with corresponding Vec fields.
src/domain/graph/builder/stages/native-orchestrator.ts Moves the native build summary query to run after JS edge post-passes so CHA/this-dispatch edges are included in the reported counts.
src/domain/wasm-worker-pool.ts Deserializes the new thisCallBindings field from the worker response into ExtractorOutput.
src/domain/wasm-worker-entry.ts Serializes thisCallBindings into the worker response so it crosses the worker-thread boundary correctly.
src/extractors/javascript.ts Backports the native class-field type-annotation extraction for TypeScript-style private repo: Repository fields so the hybrid path seeds typeMap correctly.
tests/parsers/javascript.test.ts Adds test coverage for the new pts binding kinds extracted by the WASM JS extractor.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    subgraph Native["Full-Native Path (Rust)"]
        N1[parse JS files\nJsExtractor] --> N2[8 pts binding kinds\ncollected in FileSymbols]
        N2 --> N3[Phase 8.2\npropagate_return_types\n_across_files]
        N3 --> N4[build_call_edges\nfixed-point pts solver\n4-case key gate]
        N4 --> N5[emit call / receiver /\nhierarchy edges]
    end

    subgraph Hybrid["Hybrid Path (WASM parse + native edges)"]
        H1[WASM worker parses JS\nthisCallBindings serialized\nacross worker boundary] --> H2[NativeFileEntry\nparams + 8 binding arrays\npropagated]
        H2 --> H3[Phase 8.2\npropagateReturnTypes\nAcrossFiles TS]
        H3 --> H4[native buildCallEdges FFI\nsame Rust solver]
        H4 --> H5[CHA / defineProperty\npost-passes JS only]
    end

    subgraph WASM["Pure WASM Path"]
        W1[WASM worker parses] --> W2[buildPointsToMap TS]
        W2 --> W3[buildFileCallEdges TS\n4-case key gate]
        W3 --> W4[CHA / other post-passes]
    end

    N5 & H5 & W4 --> DB[(edges table)]
Loading

Reviews (5): Last reviewed commit: "fix(native): add safety comment on max_i..." | Re-trigger Greptile

… Rust orchestrator

The JS pipeline seeds each file's typeMap with the return types of
imported factory functions (propagateReturnTypesAcrossFiles) before
edge resolution, so `const svc = buildService(); svc.createUser()`
resolves across files. The Rust orchestrator extracted returnTypeMap
and callAssignments but never consumed them, dropping those calls and
receiver edges on the native path (hybrid was unaffected because the
JS pipeline pre-seeds the typeMap it sends over napi).

Mirror the JS pass in pipeline.rs: build a per-file + global return-type
index, resolve each call assignment through the file's imports (or the
qualified Type.method global map), and inject typeMap entries at
confidence minus PROPAGATION_HOP_PENALTY, never overwriting locally
typed variables.

Verified with scripts/parity-compare.mjs: the javascript fixture now
matches exactly across wasm/native/hybrid (180 edges incl. driver.mjs
conf=0.7 calls + conf=0.75 receiver edges).
@carlos-alm

Copy link
Copy Markdown
Contributor Author

Addressed Claude's review feedback:

  • [Fixed] JS_BUILTIN_GLOBALS was missing process, window, document, and globalThis compared to the TS BUILTIN_GLOBALS set and is_js_builtin_global. Added the four missing entries in commit 9075c122. The constant now mirrors both the TS set and is_js_builtin_global exactly, preventing spurious pts edges from process.exit(), window.open(), etc.
  • [Noted/design choice] sort_targets_by_confidence in native vs TS fallback: the dedup is on (source_id, target_id) which is unique regardless of insertion order, so this cannot affect the edge set. Only the stored confidence value could differ for a multi-target call, and the benchmark green confirms no edge-level regression. Filing a follow-up issue to align confidence sorting across both paths for correctness completeness.
  • [Out-of-scope] The #[allow(clippy::too_many_arguments)] suppression follow-up refactor is tracked as a separate issue (will file below).

@carlos-alm

Copy link
Copy Markdown
Contributor Author

@greptileai

Base automatically changed from refactor/native-crate-module-layout to main June 12, 2026 02:52
@carlos-alm

Copy link
Copy Markdown
Contributor Author

Addressed all remaining feedback from the initial Claude review:

@carlos-alm

Copy link
Copy Markdown
Contributor Author

@claude

@claude

claude Bot commented Jun 12, 2026

Copy link
Copy Markdown

Claude finished @carlos-alm's task —— View job


Re-review: feat(parity): port the JS points-to solver to native and unify engine resolution

Verifying fixes from initial review

  • Verify JS_BUILTIN_GLOBALS fix — process/window/document/globalThis added
  • Verify safety comment on max_idx as usize cast
  • Scan for any new issues introduced since initial review
  • Final verdict

Verification Results

JS_BUILTIN_GLOBALS fix — ✅ Confirmed

All three sets are now identical (47 entries each):

  • src/extractors/javascript.ts BUILTIN_GLOBALS (lines 35–93)
  • crates/.../extractors/javascript.rs JS_BUILTIN_GLOBALS (lines 11–26)
  • crates/.../extractors/javascript.rs is_js_builtin_global (lines 233–255)

process, window, document, and globalThis are all present in the Rust constant. The comment on line 10 explicitly documents the invariant: "must be identical to the set tested in is_js_builtin_global". Blocker fully resolved.

Safety comment on max_idx as usize — ✅ Confirmed

build_edges.rs:246–247 now reads:

// Safety: the cast to usize is only reached inside the `max_idx >= 0` guard,
// so max_idx is non-negative here and cannot wrap to usize::MAX.
if max_idx >= 0 {
    for i in 0..=(max_idx as usize) {

Clear and correct.

No new issues found

No regressions or new parity gaps introduced by the 9075c122 / ad2d191e follow-up commits.


Final Recommendation

  • Rating: ⭐⭐⭐⭐⭐ (5/5)
  • Action: APPROVE

All blockers from the initial review are resolved. The JS_BUILTIN_GLOBALS parity gap is closed, the safety invariant is documented, and the two remaining minor findings (#1475too_many_arguments refactor, #1476sort_targets_by_confidence alignment) are correctly tracked as follow-up issues rather than blocking concerns.

This PR is in excellent shape: it fixes the root cause of native JS resolution parity (36/42 → 42/42 expected edges), does so architecturally (ports the solver rather than papering over results), removes ~360 lines of duplicated hybrid post-passes, and ships with 3600+ green tests across all three engine paths.

View job

@carlos-alm carlos-alm merged commit 204862c into main Jun 12, 2026
28 checks passed
@carlos-alm carlos-alm deleted the refactor/engine-structure-parity branch June 12, 2026 03:41
@github-actions github-actions Bot locked and limited conversation to collaborators Jun 12, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

1 participant