Skip to content

Add virtual-twin type-identity regression tests (#229) - #240

Closed
NullVoxPopuli-ai-agent wants to merge 1 commit into
ember-tooling:mainfrom
NullVoxPopuli-ai-agent:test/virtual-twin-regression
Closed

Add virtual-twin type-identity regression tests (#229)#240
NullVoxPopuli-ai-agent wants to merge 1 commit into
ember-tooling:mainfrom
NullVoxPopuli-ai-agent:test/virtual-twin-regression

Conversation

@NullVoxPopuli-ai-agent

Copy link
Copy Markdown

Tests extracted from #235 so the fix and its regression tests can be reviewed separately. Merge #235 first — these tests intentionally fail against the current parser; the failures are the #229 bug.

What's covered

Three assertions, each run under both project and projectService (the service mode is feature-detected: its option spelling varies across typescript-eslint majors, and v7's experimental service can't hold .gts files in-project, so it's registered only when a probe parse yields a program that actually contains virtual twins — 3 tests on tsee 7, 6 on tsee 8):

  1. Every virtual twin is grafted — the .ts resolution virtual and (where present) the .mts readDirectory twin share statements with the .gts root.
  2. One type identity across import paths — a class with a private member resolves to the identical type object via the .gts root and via its virtual twins, and is assignable to itself in both directions.
  3. No re-graft of an already-synced program — a canary planted on a twin after binding survives a later parse; without the once-per-program guard the graft rewrites binder state under a live checker on every parse.

Expected failures without #235

Which tests fail depends on the toolchain, because the .mts twin only appears in the program on newer TS versions:

  • current default toolchain (TS 5.7): the two re-graft canary tests fail (2 failed | 4 passed);
  • TS 6 matrix cells: the twin-graft and type-identity tests fail as well, since the old code grafts only the .mts twin and leaves the .ts virtual — the copy every extensionless import resolves to — ungrafted.

After #235, all 6 pass on every matrix cell (verified on #235's CI before the split).

🤖 Generated with Claude Code

Covers the graft behavior fixed in ember-tooling#235, under both project and
projectService (feature-detected; v7's experimental service can't hold
.gts files in-project, so the mode is registered only when a probe
parse yields a program that contains virtual twins):

- every virtual twin present shares statements with the .gts root,
- a private-member class has one type identity across import paths,
- an already-synced program is not re-grafted on later parses.

These tests FAIL against the parser without ember-tooling#235 — that failure is the
ember-tooling#229 bug (distinct class symbols per import path, binder state
rewritten under a live checker). Merge ember-tooling#235 first.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

🏎️ Benchmark Comparison

Parse

Benchmark Control (p50) Experiment (p50) Δ
🟢 gts small 932.55 ms 895.54 ms -4.0%
gts medium 1611.63 ms 1599.94 ms -0.7%
gts large 813.39 ms 820.17 ms +0.8%
gjs small 798.10 ms 794.37 ms -0.5%
🟢 gjs medium 1387.77 ms 1356.98 ms -2.2%
🟢 gjs large 638.02 ms 621.16 ms -2.6%
🟠 hbs small 129.71 ms 134.83 ms +3.9%
🟠 hbs medium 725.35 ms 750.22 ms +3.4%
🟠 hbs large 815.97 ms 844.56 ms +3.5%

🟢 faster · 🔴 slower · 🟠 slightly slower · ⚪ within 2%

Full mitata output
clk: ~3.10 GHz
cpu: AMD EPYC 7763 64-Core Processor
runtime: node 24.18.0 (x64-linux)

benchmark                   avg (min … max) p75 / p99    (min … top 1%)
------------------------------------------- -------------------------------
gts small (control)          986.20 ms/iter    1.01 s       █              
                       (838.34 ms … 1.30 s)    1.13 s ▅  ▅▅▅█ ▅ ▅ ▅  ▅    ▅
                    ( 13.07 mb …  88.44 mb)  42.57 mb █▁▁████▁█▁█▁█▁▁█▁▁▁▁█

gts small (experiment)       946.45 ms/iter 980.60 ms   █                  
                       (819.28 ms … 1.30 s)    1.09 s   █                  
                    ( 12.56 mb …  83.89 mb)  41.88 mb ███▁▁▁██▁▁▁██▁█▁▁▁▁▁█

                             ┌                                            ┐
                                ╷       ┌────────────┬──┐                 ╷
         gts small (control)    ├───────┤            │  ├─────────────────┤
                                ╵       └────────────┴──┘                 ╵
                             ╷   ┌─────────────┬────┐               ╷
      gts small (experiment) ├───┤             │    ├───────────────┤
                             ╵   └─────────────┴────┘               ╵
                             └                                            ┘
                             819.28 ms           975.81 ms           1.13 s

summary
  gts small (experiment)
   1.04x faster than gts small (control)

------------------------------------------- -------------------------------
gts medium (control)            1.69 s/iter    1.72 s  █     █             
                          (1.54 s … 2.09 s)    1.87 s ▅█▅▅ ▅ █   ▅      ▅ ▅
                    ( 80.02 mb …  99.53 mb)  84.32 mb ████▁█▁█▁▁▁█▁▁▁▁▁▁█▁█

gts medium (experiment)         1.66 s/iter    1.69 s     █                
                          (1.50 s … 2.19 s)    1.71 s ▅   █▅▅  ▅ ▅ ▅    ▅▅▅
                    ( 79.72 mb …  99.72 mb)  84.29 mb █▁▁▁███▁▁█▁█▁█▁▁▁▁███

                             ┌                                            ┐
                                 ╷  ┌──────────────┬────┐                 ╷
        gts medium (control)     ├──┤              │    ├─────────────────┤
                                 ╵  └──────────────┴────┘                 ╵
                             ╷    ┌─────────────┬────┐ ╷
     gts medium (experiment) ├────┤             │    ├─┤
                             ╵    └─────────────┴────┘ ╵
                             └                                            ┘
                             1.50 s              1.69 s              1.87 s

summary
  gts medium (experiment)
   1.02x faster than gts medium (control)

------------------------------------------- -------------------------------
gts large (control)          852.69 ms/iter 845.01 ms       ███     █      
                       (779.39 ms … 1.21 s) 875.81 ms ▅  ▅  ███     █     ▅
                    ( 14.87 mb …  86.21 mb)  33.23 mb █▁▁█▁▁███▁▁▁▁▁█▁▁▁▁▁█

gts large (experiment)       877.88 ms/iter 881.67 ms    █                 
                       (789.08 ms … 1.22 s) 981.98 ms    █                 
                    ( 15.01 mb …  87.11 mb)  38.29 mb ████▁█▁█▁▁█▁▁█▁▁▁▁▁▁█

                             ┌                                            ┐
                             ╷     ┌─────────┬    ╷
         gts large (control) ├─────┤         │────┤
                             ╵     └─────────┴    ╵
                               ╷    ┌──────────────┬┐                     ╷
      gts large (experiment)   ├────┤              │├─────────────────────┤
                               ╵    └──────────────┴┘                     ╵
                             └                                            ┘
                             779.39 ms         880.68 ms          981.98 ms

summary
  gts large (control)
   1.03x faster than gts large (experiment)

------------------------------------------- -------------------------------
gjs small (control)          827.98 ms/iter 831.59 ms       █              
                       (752.58 ms … 1.11 s) 903.69 ms  █    █              
                    ( 29.21 mb …  85.87 mb)  37.07 mb ████▁▁█▁▁▁█▁▁▁▁▁█▁▁▁█

gjs small (experiment)       823.65 ms/iter 838.91 ms        █             
                       (736.67 ms … 1.11 s) 912.31 ms    █   █    █        
                    ( 29.42 mb …  85.80 mb)  37.09 mb █▁███▁▁█▁▁▁▁█▁▁▁▁▁▁▁█

                             ┌                                            ┐
                                 ╷ ┌────────────────┬┐                  ╷
         gjs small (control)     ├─┤                │├──────────────────┤
                                 ╵ └────────────────┴┘                  ╵
                             ╷     ┌───────────────┬───┐                  ╷
      gjs small (experiment) ├─────┤               │   ├──────────────────┤
                             ╵     └───────────────┴───┘                  ╵
                             └                                            ┘
                             736.67 ms         824.49 ms          912.31 ms

summary
  gjs small (experiment)
   1.01x faster than gjs small (control)

------------------------------------------- -------------------------------
gjs medium (control)            1.44 s/iter    1.44 s █     █              
                          (1.33 s … 1.83 s)    1.50 s █  ▅ ▅█ ▅  ▅ ▅  ▅   ▅
                    ( 21.00 mb …  88.88 mb)  71.13 mb █▁▁█▁██▁█▁▁█▁█▁▁█▁▁▁█

gjs medium (experiment)         1.42 s/iter    1.44 s       █              
                          (1.30 s … 1.85 s)    1.46 s       █              
                    ( 18.94 mb …  88.99 mb)  70.53 mb █▁▁▁█▁██▁▁█▁▁▁█▁▁█▁██

                             ┌                                            ┐
                                    ╷     ┌─────────────────┬┐            ╷
        gjs medium (control)        ├─────┤                 │├────────────┤
                                    ╵     └─────────────────┴┘            ╵
                             ╷          ┌───────────────┬──┐     ╷
     gjs medium (experiment) ├──────────┤               │  ├─────┤
                             ╵          └───────────────┴──┘     ╵
                             └                                            ┘
                             1.30 s              1.40 s              1.50 s

summary
  gjs medium (experiment)
   1.01x faster than gjs medium (control)

------------------------------------------- -------------------------------
gjs large (control)          680.03 ms/iter 647.81 ms   █                  
                    (617.35 ms … 975.45 ms) 784.17 ms   █▅                 
                    (219.87 kb …  69.98 mb)  43.76 mb ▇▇██▇▁▁▁▇▁▁▁▁▁▁▁▁▁▁▁▇

gjs large (experiment)       669.27 ms/iter 640.83 ms   ███                
                    (595.59 ms … 983.07 ms) 788.31 ms ▅▅███▅  ▅           ▅
                    (886.13 kb …  70.13 mb)  43.78 mb ██████▁▁█▁▁▁▁▁▁▁▁▁▁▁█

                             ┌                                            ┐
                                  ╷   ┌──────────┬                       ╷
         gjs large (control)      ├───┤          │───────────────────────┤
                                  ╵   └──────────┴                       ╵
                             ╷    ┌───────────┬                           ╷
      gjs large (experiment) ├────┤           │───────────────────────────┤
                             ╵    └───────────┴                           ╵
                             └                                            ┘
                             595.59 ms         691.95 ms          788.31 ms

summary
  gjs large (experiment)
   1.02x faster than gjs large (control)

------------------------------------------- -------------------------------
hbs small (control)          148.24 ms/iter 154.02 ms       █           █  
                    (113.03 ms … 288.91 ms) 159.20 ms ▅ ▅  ▅█▅   ▅  ▅   █ ▅
                    ( 51.37 mb …  55.90 mb)  53.49 mb █▁█▁▁███▁▁▁█▁▁█▁▁▁█▁█

hbs small (experiment)       149.59 ms/iter 151.11 ms           █          
                    (111.17 ms … 291.62 ms) 159.99 ms           █     █   █
                    ( 51.22 mb …  55.69 mb)  53.51 mb █▁█▁▁██▁▁▁█▁▁▁▁▁█▁▁▁█

                             ┌                                            ┐
                               ╷         ┌─────────────────────┬────┐    ╷
         hbs small (control)   ├─────────┤                     │    ├────┤
                               ╵         └─────────────────────┴────┘    ╵
                             ╷          ┌───────────────────────┬─┐       ╷
      hbs small (experiment) ├──────────┤                       │ ├───────┤
                             ╵          └───────────────────────┴─┘       ╵
                             └                                            ┘
                             111.17 ms         135.58 ms          159.99 ms

summary
  hbs small (control)
   1.01x faster than hbs small (experiment)

------------------------------------------- -------------------------------
hbs medium (control)         757.70 ms/iter 745.29 ms    █ █  █           █
                    (699.51 ms … 992.38 ms) 795.09 ms ▅  █▅█  █ ▅         █
                    (  8.88 mb …  81.68 mb)  38.01 mb █▁▁███▁▁█▁█▁▁▁▁▁▁▁▁▁█

hbs medium (experiment)      779.92 ms/iter 782.95 ms ██  █                
                    (727.45 ms … 997.89 ms) 840.46 ms ██▅ █   ▅ ▅  ▅      ▅
                    (  8.57 mb …  81.81 mb)  32.61 mb ███▁█▁▁▁█▁█▁▁█▁▁▁▁▁▁█

                             ┌                                            ┐
                             ╷   ┌──────────────┬           ╷
        hbs medium (control) ├───┤              │───────────┤
                             ╵   └──────────────┴           ╵
                                      ╷ ┌──────────────┬┐                 ╷
     hbs medium (experiment)          ├─┤              │├─────────────────┤
                                      ╵ └──────────────┴┘                 ╵
                             └                                            ┘
                             699.51 ms         769.99 ms          840.46 ms

summary
  hbs medium (control)
   1.03x faster than hbs medium (experiment)

------------------------------------------- -------------------------------
hbs large (control)          837.80 ms/iter 819.69 ms      █               
                       (797.73 ms … 1.06 s) 869.97 ms   █  █               
                    ( 53.35 mb …  64.87 mb)  55.49 mb █▁█████▁▁█▁▁▁▁▁▁▁▁▁▁█

hbs large (experiment)       868.41 ms/iter 861.36 ms       ██             
                       (817.20 ms … 1.09 s) 899.91 ms       ██             
                    ( 53.47 mb …  64.84 mb)  55.48 mb ██▁▁▁▁██▁▁▁██▁▁▁▁▁▁▁█

                             ┌                                            ┐
                             ╷   ┌─────────────┬             ╷
         hbs large (control) ├───┤             │─────────────┤
                             ╵   └─────────────┴             ╵
                                      ╷         ┌───────────┬             ╷
      hbs large (experiment)          ├─────────┤           │─────────────┤
                                      ╵         └───────────┴             ╵
                             └                                            ┘
                             797.73 ms         848.82 ms          899.91 ms

summary
  hbs large (control)
   1.04x faster than hbs large (experiment)
### Project mode (type-aware)
Benchmark Control (p50) Experiment (p50) Δ
🟢 project warm parse x150 618.74 ms 580.41 ms -6.2%
project parse+typed x150 624.33 ms 625.00 ms +0.1%
projectService warm parse x150 607.25 ms 616.43 ms +1.5%
🔴 projectService parse+typed x150 705.66 ms 809.54 ms +14.7%

🟢 faster · 🔴 slower · 🟠 slightly slower · ⚪ within 2%

Full mitata output
clk: ~2.91 GHz
cpu: AMD EPYC 7763 64-Core Processor
runtime: node 24.18.0 (x64-linux)

benchmark                                   avg (min … max) p75 / p99    (min … top 1%)
----------------------------------------------------------- -------------------------------
project warm parse x150 (control)            614.53 ms/iter 622.13 ms                █     
                                    (584.58 ms … 663.41 ms) 630.12 ms ▆▆▁▁▆▆▁▁▁▁▁▁▁▁▆█▆▆▁▁▆
                                  gc(290.31 ms … 310.97 ms) 113.10 mb (109.83 mb…114.81 mb)

project warm parse x150 (experiment)         586.47 ms/iter 598.11 ms █   █             █  
                                    (572.90 ms … 606.59 ms) 600.95 ms █▁█▁██▁█▁▁▁▁█▁▁▁▁▁█▁█
                                  gc(282.61 ms … 318.06 ms) 110.61 mb (107.13 mb…112.49 mb)

                                             ┌                                            ┐
                                                      ╷      ┌────────────────┬─────┐     ╷
           project warm parse x150 (control)          ├──────┤                │     ├─────┤
                                                      ╵      └────────────────┴─────┘     ╵
                                             ╷ ┌────────┬────────┐ ╷
        project warm parse x150 (experiment) ├─┤        │        ├─┤
                                             ╵ └────────┴────────┘ ╵
                                             └                                            ┘
                                             572.90 ms         601.51 ms          630.12 ms

summary
  project warm parse x150 (experiment)
   1.05x faster than project warm parse x150 (control)

----------------------------------------------------------- -------------------------------
project parse+typed x150 (control)           626.15 ms/iter 634.56 ms █  █   █ ██ ██ ███  █
                                    (598.70 ms … 660.14 ms) 642.64 ms █▁▁█▁▁▁█▁██▁██▁███▁▁█
                                  gc(291.42 ms … 305.84 ms) 118.85 mb (117.83 mb…122.53 mb)

project parse+typed x150 (experiment)        626.62 ms/iter 638.11 ms █                  █ 
                                    (601.25 ms … 671.06 ms) 640.23 ms █▁▁█▁▁▁██▁▁▁█▁▁█▁█▁██
                                  gc(297.53 ms … 315.91 ms) 117.24 mb (116.11 mb…121.95 mb)

                                             ┌                                            ┐
                                             ╷               ┌───────────┬────────┐       ╷
          project parse+typed x150 (control) ├───────────────┤           │        ├───────┤
                                             ╵               └───────────┴────────┘       ╵
                                                ╷    ┌────────────────────┬──────────┐  ╷
       project parse+typed x150 (experiment)    ├────┤                    │          ├──┤
                                                ╵    └────────────────────┴──────────┘  ╵
                                             └                                            ┘
                                             598.70 ms         620.67 ms          642.64 ms

summary
  project parse+typed x150 (control)
   1x faster than project parse+typed x150 (experiment)

----------------------------------------------------------- -------------------------------
projectService warm parse x150 (control)     616.90 ms/iter 621.83 ms ██          █        
                                    (596.99 ms … 671.85 ms) 640.01 ms ██▁▁██▁▁▁▁███▁▁▁▁▁▁▁█
                                  gc(301.96 ms … 373.07 ms) 113.59 mb (108.46 mb…116.12 mb)

projectService warm parse x150 (experiment)  630.43 ms/iter 629.82 ms   █                  
                                    (612.34 ms … 670.12 ms) 659.80 ms ▅▅█▁▁▁▅█▁▁▁▁▁▁▁▁▁▁▁▅▅
                                  gc(304.66 ms … 327.75 ms) 111.61 mb (110.98 mb…111.95 mb)

                                             ┌                                            ┐
                                             ╷ ┌───────────┬───┐            ╷
    projectService warm parse x150 (control) ├─┤           │   ├────────────┤
                                             ╵ └───────────┴───┘            ╵
                                                        ╷  ┌─────────┬                    ╷
 projectService warm parse x150 (experiment)            ├──┤         │────────────────────┤
                                                        ╵  └─────────┴                    ╵
                                             └                                            ┘
                                             596.99 ms         628.40 ms          659.80 ms

summary
  projectService warm parse x150 (control)
   1.02x faster than projectService warm parse x150 (experiment)

----------------------------------------------------------- -------------------------------
projectService parse+typed x150 (control)    708.68 ms/iter 718.40 ms             █ █     █
                                    (652.99 ms … 753.50 ms) 737.68 ms █▁▁▁▁▁▁█▁██▁█▁██▁▁▁▁█
                                  gc(308.80 ms … 347.28 ms) 119.58 mb (118.80 mb…124.31 mb)

projectService parse+typed x150 (experiment) 807.58 ms/iter 815.93 ms         █     ▃      
                                    (766.57 ms … 849.41 ms) 833.31 ms ▆▁▁▁▁▆▁▁█▁▁▁▁▆█▆▁▁▁▆▆
                                  gc(342.64 ms … 369.56 ms) 118.38 mb (117.24 mb…122.26 mb)

                                             ┌                                            ┐
                                             ╷         ┌───┬─┐    ╷
   projectService parse+typed x150 (control) ├─────────┤   │ ├────┤
                                             ╵         └───┴─┘    ╵
                                                                         ╷      ┌───┬─┐   ╷
projectService parse+typed x150 (experiment)                             ├──────┤   │ ├───┤
                                                                         ╵      └───┴─┘   ╵
                                             └                                            ┘
                                             652.99 ms         743.15 ms          833.31 ms

summary
  projectService parse+typed x150 (control)
   1.14x faster than projectService parse+typed x150 (experiment)

NullVoxPopuli-ai-agent pushed a commit to NullVoxPopuli-ai-agent/ember-eslint-parser that referenced this pull request Jul 6, 2026
Three assertions, each under both project and projectService
(feature-detected; v7's experimental service can't hold .gts files
in-project, so the mode is registered only when a probe parse yields a
program that contains virtual twins — 3 tests on tsee 7, 6 on tsee 8):

- every virtual twin present shares statements with the .gts root,
- a private-member class has one type identity across import paths,
- an already-synced program is not re-grafted on later parses.

Against the unfixed parser these fail — demonstrated on CI in ember-tooling#240:
the re-graft canaries fail on TS 5.7, and the twin-graft/type-identity
tests additionally fail on TS 6 cells where the .mts twin shadows the
old single-candidate fallback.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@NullVoxPopuli-ai-agent

Copy link
Copy Markdown
Author

Served its purpose: the CI run on this PR demonstrates these tests failing against the unfixed parser — Tests / Tests (Node 20) red with the re-graft canaries failing on TS 5.7 (the TS 6 matrix cells, where the twin-graft and type-identity tests also fail, were skipped by fail-fast). The tests are folded back into #235, where they pass against the fix.

@NullVoxPopuli-ai-agent
NullVoxPopuli-ai-agent deleted the test/virtual-twin-regression branch July 6, 2026 17:08
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