Skip to content

feat: framework resolvers, synthesis, VB.NET and codegraph context - #338

Draft
sunerpy wants to merge 19 commits into
mainfrom
feat/v0.56-followups
Draft

sunerpy wants to merge 19 commits into
mainfrom
feat/v0.56-followups

Conversation

@sunerpy

@sunerpy sunerpy commented Oct 23, 2026

Copy link
Copy Markdown
Owner

Summary

The v0.56.0 follow-up program: the work split out of v0.55 (OD-18) plus the
items that came after it. This PR stays a draft while the waves land; each
wave is pushed when its local gate passes.

Planned scope:

  • W0 foundations (this push)
  • W7 UI families and framework resolvers (F1-F12, synthesis stage, framework
    resolvers)
  • W8 VB.NET
  • W9 codegraph context, upstream #1617, and the v1.5.0 performance strategies
  • W10 documentation, upstream ledger and release preparation

W0 (pushed)

  • Extraction version 22 → 23 as the first commit, before any change in
    graph meaning, so users rebuild once. upgrade_from_v055 covers the
    v0.55 → v0.56 path (a v0.55 index is Outdated{22} and upgrades to a
    graph equal to a fresh init).
  • Refuse a schema newer than the binary (OD-19) without writing:
    StoreError::FutureSchema from every opening path (sync, daemon catch-up,
    MCP sessions, rebuild), probed WAL-aware before any writable open. The
    recovery text offers uninit only where uninit would succeed.
    uninit --force can still discard such an index.
  • uninit --force beside a leftover tombstone: a current index next to
    the uninit tombstone is now discarded (the tombstone stays, so only init
    rebuilds it), and a newer schema is reported before the tombstone.
  • Rust member-path std gate: no code needed; a probe pins that
    std-typed receivers (PathBuf, &Path) stay unresolved.
  • MCP engine test directories no longer collide on a reused pid.
  • Dependencies: the Cargo updates from build(deps): bump the cargo group across 1 directory with 6 updates #334 except tree-sitter-swift,
    which stays at 0.7.3 (0.7.4 regenerates the grammar; documented in
    docs/grammar-manifest.md).

Verification (W0, HEAD 5cb5f32)

  • make check: 239 suites, 6135 passed, 0 failed, 1 ignored.
  • make pre-ci (pre-push hook): passed, including the viewer bundle byte
    check and the release-archive smoke.
  • Extraction goldens unchanged (scripts/regen-goldens.sh --check); graph
    diffs over the precision corpora identical before and after the dependency
    updates.
  • Benchmark quick check (fd-small, tokio-medium; 32 and 4 threads; 6 runs)
    within budget.

Not in this PR yet

W7-W10. This description is updated as each wave is pushed.

v0.56 changes graph meaning (framework resolvers, synthesis, VB.NET,
grammar bumps), so the extraction version moves once, first, to 23. A
v0.55 index (schema 10, extraction version 22) is Outdated and upgrades
through the existing full migration; v0.55 reports a version-23 index as
Future and writes nothing.

- upgrade_from_v055 covers the paths upgrade_from_v054 covers (CLI sync,
  catch-up, the cold MCP session's daemon upgrade, an older uninit stays
  Uninitialized, a failed upgrade still refuses, interrupted builds,
  tombstones and missing databases are skipped) over a fixture the
  official v0.55.2 linux-musl binary wrote; checksum, attestation and
  commands are in its README. The shared helpers move to
  tests/upgrade_support unchanged.
- upgrade_from_schema_9 downgrades a fresh init of the mini corpus to
  schema 9 instead of planting rows from 3878d52, so its comparison with
  a fresh init checks only the migration. The release fixture keeps a
  third test that checks the in-place migration alone.
A database whose schema_versions records a version above this binary's
was written by a newer codegraph (OD-19). Reads, status, sync, MCP, the
daemon, init and index --force now refuse it before they change a byte,
and the error names both versions. ensure_schema_and_migrations returns
MigrationError::NewerSchema before it creates a table, migrates or
analyzes.

The newer version may sit only in an un-checkpointed write-ahead log.
The writers that tolerate a live log (an incremental sync, the daemon's
recovery of a dead owner's log) and every rebuild entry (before an
explicit init removes a copied project's state slots, before a lockless
root gets its lock, before building is published) decide from
schema_probe: the main file plus the log's committed frames, applied in
memory the way SQLite's recovery does, so no -wal or -shm is created or
folded. A file that is not SQLite is still replaced; a database whose
version cannot be read is refused, and the error says nothing changed.

uninit --force skips the check and stays the way to discard such an
index; the refusal offers it only for the states uninit accepts. status
reports the index as current with initialized false and both versions.
test_engine() returned an engine over /tmp/cg-mcp-engine-{pid}-{seq} and
never removed the directory, so a reused pid opened a stale index and
engine tests failed locally. TestEngine derefs to the engine, removes a
stale directory before it creates one, and on drop closes the engine
before removing its directory.
The member-path std gate deferred on 2026-10-03 needs no code: the v0.55
port of upstream #2169 already keeps a receiver whose declared type the
project does not declare (PathBuf, &Path, std::path::PathBuf) from
binding a project method by name. The probe pins it: index_root.join,
base.join, p.join and q.join stay unresolved and reach no
LineIndex::join, while env.set() still reaches EnvGuard::set.
Takes dependabot #334 except tree-sitter-swift: tree-sitter 0.27.1,
tree-sitter-language 0.1.9, erlang 0.21.0, php 0.25.1, scala =0.26.3,
cfml 0.26.43, and the windows-sys reselection. Every golden, the four
precision corpora and this repository index identically before and after.

tree-sitter-swift stays at =0.7.3 (OD-B4). 0.7.4 fixes the scanner line
behind upstream #2683 (`1UL << 32`, which MSVC folds to 0, so the Windows
build reads `try! Foo()` as a call of `! Foo`), but it also regenerates
the grammar: a call after an infix or prefix operator (`a + b.c()`,
`!a.b()`) comes out as another tree, which the walker does not read as a
member call. Upgrading it lost an exact-match edge in the swift golden and
turned two Alamofire callees into whole expressions; the upgrade waits for
that walker change.

The #2683 probe pins calls after try!, try? and try. It is ignored on
Windows until the upgrade; with the scanner line changed to what MSVC
compiles it to, it fails on Linux the way upstream observed on Windows.
No real Windows host was used. The grammar manifest records the held
version, and languages.md the Windows limitation.
A Current index beside the uninit tombstone (an init that published
Current but could not remove it) refused uninit --force with
CurrentTombstoned. With a schema a newer codegraph wrote, init refuses
that index and names uninit --force, so the refusal pointed at a command
that then failed.

Uninit's corroboration now accepts the tombstone: it discards the index
like any other Current one and keeps the tombstone, so only init
rebuilds it. Covered with and without a newer schema, in the store and
through the CLI.
A Current index beside the uninit tombstone was reported as tombstoned
before its schema was read, so status named `codegraph init` as the
recovery even when a newer codegraph wrote the database, and init then
refused it.

When the tombstone is present, the corroboration now reads the schema
version first (the write-ahead-log-aware probe, which touches no file);
a positively newer version is FutureSchema, which offers uninit --force.
Any other outcome is still CurrentTombstoned, so the same-version
contract and its init recovery are unchanged.
A refusal of a newer codegraph's index offered `uninit --force` for every
state uninit accepts, but on a Current namespace uninit first corroborates
the database's extraction stamp. With the stamp missing, malformed or not
this binary's, the offered command then failed.

The offer now runs the same read-only corroboration uninit runs before
its first change, for the tombstone precedence in the read gate and for
the rebuild prologue. A newer schema with a bad stamp, tombstoned or not,
is refused without the offer.
status's human output for an index a newer codegraph wrote always named
`uninit --force`, even when the refusal it reports does not offer it
because uninit would refuse the index (a missing or foreign extraction
stamp). It now follows the refusal: upgrade, plus the uninit recovery
only where uninit would discard the index.
Moving the shared helpers to tests/upgrade_support left
upgrade_from_v054 and upgrade_from_v055 using ExtractionStatus and Store
only in their unix-only tests, so the Windows Clippy job failed on
unused imports. The import is now cfg(unix).
@codecov

codecov Bot commented Oct 23, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 94.10825% with 369 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
crates/codegraph-graph/src/branch_guards.rs 90.30% 178 Missing ⚠️
crates/codegraph-resolve/src/resolver.rs 89.88% 45 Missing ⚠️
crates/codegraph-store/src/connection.rs 69.23% 32 Missing ⚠️
...s/codegraph-resolve/src/frameworks/package_deps.rs 94.21% 29 Missing ⚠️
crates/codegraph-resolve/src/frameworks/nestjs.rs 98.29% 17 Missing ⚠️
crates/codegraph-graph/src/synthesized_hop.rs 95.45% 12 Missing ⚠️
crates/codegraph-store/src/schema_probe.rs 95.23% 12 Missing ⚠️
crates/codegraph-resolve/src/frameworks/js_scan.rs 97.10% 8 Missing ⚠️
crates/codegraph-resolve/src/framework.rs 33.33% 6 Missing ⚠️
crates/codegraph-resolve/src/js_store.rs 0.00% 6 Missing ⚠️
... and 8 more

❌ Your patch check has failed because the patch coverage (94.10%) is below the target coverage (95.00%). You can increase the patch coverage or adjust the target coverage.

Impacted file tree graph

@@            Coverage Diff             @@
##             main     #338      +/-   ##
==========================================
- Coverage   95.59%   95.56%   -0.03%     
==========================================
  Files         280      286       +6     
  Lines      166519   171840    +5321     
==========================================
+ Hits       159181   164219    +5038     
- Misses       7338     7621     +283     
Files with missing lines Coverage Δ
crates/codegraph-core/src/types.rs 100.00% <100.00%> (ø)
crates/codegraph-graph/src/flow_boundary.rs 93.87% <100.00%> (+0.12%) ⬆️
crates/codegraph-graph/src/graph/mod.rs 94.67% <100.00%> (+<0.01%) ⬆️
crates/codegraph-graph/src/named_symbol_flow.rs 86.50% <100.00%> (+1.52%) ⬆️
crates/codegraph-resolve/src/cfml_scope.rs 97.60% <100.00%> (ø)
crates/codegraph-resolve/src/context.rs 99.32% <100.00%> (+<0.01%) ⬆️
crates/codegraph-resolve/src/cpp_namespaces.rs 96.25% <100.00%> (+0.01%) ⬆️
crates/codegraph-resolve/src/cpp_supertypes.rs 86.22% <100.00%> (+0.04%) ⬆️
crates/codegraph-resolve/src/csharp_extensions.rs 95.36% <100.00%> (ø)
crates/codegraph-resolve/src/dart_annotations.rs 92.88% <100.00%> (-0.04%) ⬇️
... and 42 more

... and 3 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

The groundwork the routers of the next commits draw their edges with
(F1, upstream #2129 and #2395). No registered resolver uses the new
pieces yet, so every golden and the express, typescript-large and
self-index graphs are unchanged.

- EdgeKind::Navigates, stored as text like every edge kind. Callers,
  callees, the named-symbol flow and a flow's boundary follow it, as
  upstream's traversal, FLOW_EDGE_KINDS and CONTINUATION_KINDS do.
- A ResolvedRef can carry an EdgeShape (upstream edgeKind, metadata and
  alsoTargets): the edges' kind, the metadata on the target's edge, and
  more targets, each its own edge under the same kind and confidence.
  ResolvedRef::new builds the plain resolution every resolver returned
  before.
- frameworks/package_deps reads the dependencies a project declares in
  its root package.json and up to 24 nested ones: one or two directories
  down, then deeper above JavaScript-family code, never inside
  node_modules. React and NestJS detect through it, so an app whose
  manifest is in frontend/, apps/web/ or src/Web/ClientApp/ is detected
  without its fallback evidence. Upstream package-deps.ts is unchanged
  between b635dd46 and e8ddc4e2.
- A framework can name its app dependencies (appDependencies). When a
  manifest declares one, its extractor runs only on files whose nearest
  package.json naming such a framework names it. The frameworks row a
  sync compares adds a digest of where each gated framework runs, so a
  manifest edit that moves an app re-extracts every file, as a framework
  that came or went does. The JS control inputs digest every manifest
  detection may read, so a sync notices one appearing beside no script.
- The trait gains cross_file_nodes and navigation (upstream #2400 and
  #2425), both None by default; nothing calls them until a router
  implements them.

The sync matrix gains two cases: React declared in an app's manifest,
and in a manifest one directory down above no script. The gating sync
case waits for the first gated framework (W7-07).
An edge a framework resolver made now names that resolver in
metadata.framework (upstream #2159), as a synthesized edge names its
pass in synthesizedBy: a Tauri invoke('greet') says `tauri`, a Godot
autoload call `godot`. The orchestrator adds it to every result a
framework's resolve returns, before the confidence race, so a lower
confidence framework result that wins later carries it too. When a
resolution reaches several targets, only the edge to the first carries
it, as upstream's does; the others keep the metadata the resolver gave
each.

Goldens: godot's four autoload calls and routers' one Vue-resolved call
gain the key; no edge, node or reference comes or goes. The same holds
for this repository (2 edges) and typescript-large (590 edges, all
`react`).
Framework detection reads the manifests one or two directories down from
every indexed file, whatever its language (upstream #2395), and the JS
control-input row digests every such candidate. The watcher re-read that
row only when a JS-family file came or went, so a file of another language
arriving in a new directory left the row behind a fresh index: 39 cases of
the sync matrix (CFML, C, C++, C#, Dart, Go, Java, Kotlin, Liquid, Lua,
Objective-C, PHP, Python, Rust and Solidity edits) failed under the watch
driver. The graph itself converged, since a sync with changes re-detects
the frameworks anyway.

The control-input check now counts any file that comes or goes as touching
the JS kind. typescript_react_dependency_beside_an_added_script covers it
directly: React declared in frontend/package.json is detected once
frontend/build.py is indexed, and the sync records that manifest as a fresh
index does.
…ts; typed styled components

React resolution now follows upstream b635dd46 (#2120's React half,
#2240, #2429, #841, #2475's static half and #2420's wrapper half):

- A component, hook or context the file imports is the import's: a
  UI kit's `<Button>` or @tanstack/react-query's `useQuery` no longer
  binds a project namesake, and a project module's is import
  resolution's to find (#2120, #2475).
- A hook nested inside another function is never a target, and the
  file's own hook comes first (#2120). In a JS/TS module another file's
  hook or context is reached only through an import, never by bare name
  (#2240), and `f?.()` is a bare call, so an optional call no longer
  binds a class member or a property.
- A PascalCase name a .tsx/.jsx file declares as a module-level value
  is that declaration wherever the file uses it: the function the value
  wraps (`observer(function X() {…})`, `forwardRef(Inner) as …`), else
  the declaration, never another app's same-named component (#2420).
  The lazy loader half needs W7-09's reader.
- A PascalCase const declared through forwardRef/memo (bare or `React.`)
  or a styled-components/emotion tag (`styled.x`…``, `styled(Base)`…``,
  typed `styled.x<P>`…``, #2429) is a `component` node, and an inline
  render function's calls are the component's (#841). React's extract no
  longer mints regex component/hook duplicates of tree-sitter nodes; it
  emits routes only, now from .tsx/.jsx files too.

js_scan ports the bracket and string scanner upstream reads declarations
with, iteratively, so deeply nested source cannot exhaust the stack.

Goldens: routers gains the four .tsx page and data-router routes and one
route -> Layout edge; synthesis loses the regex `useCartStore` hook node
(log row in docs/equivalence.md). Precision: express-medium identical;
this repository +4 routes, -8 regex hook duplicates, and a Svelte
`onclose?.()` is now unresolved, as upstream; typescript-large and
LibreChat sampled 20 + 20 rows each, no wrong edge introduced.

LibreChat loses 919 reference sites in the interim: 857 behind the
`~/` alias its client/tsconfig.json declares (Rust reads only the root
tsconfig; upstream #2165's nearest-config aliases come with W7-09) and
62 rendering a module whose default export is `memo(X)` (#2563's
static half, W7-09). Upstream landed #2120 before #2165 the same way.

The sync matrix gains tsx_route_element_body_edit and
tsx_wrapper_value_body_edit; the react_dependency cases observe a data
router's route instead of a regex hook node. Upstream's later react.ts
rows #2737 (PORT) and #2738 (PARTIAL) are left for the next round.
…sioning

In a TS/JS module the provider convention (`*Service`, `*Controller`, …)
now takes only the reference's own class or the convention file beside
it (users.controller.ts -> users.service.ts); anything farther is import
resolution's or name matching's (upstream #2246). Nest's own specs'
`TransientService` no longer reaches an integration app's, and a
decorator call `@Controller('users')` no longer instantiates a PHP class
named `Controller`.

A NestJS route is named by the path a request takes to it (upstream
#2117). post_extract reads each `NestFactory.create` bootstrap and
renames the routes of its app's controllers in NestJS's order,
`/{prefix}/{v}{version}/{RouterModule prefix}/{path}`:

- `exclude` paths (plain, `{ path, method }`, `{/*wildcard}`, `(.*)`,
  `*`) skip the prefix and keep their version;
- a route's version is its own `@Version` (found past decorators with
  object arguments), else its class's `@Version` or `@Controller({
  version })`, else `defaultVersion`; `VERSION_NEUTRAL` has none, and
  header or media-type versioning adds no segment;
- a computed prefix is not guessed; each app takes the bootstrap with
  the longest root above it, a seed script that creates the app without
  serving it does not displace the one that configures it, and an app
  that sets nothing keeps its routes as written;
- only a route whose decorator sits in a `@Controller` is renamed.

A route keeps its id and qualified name. One an earlier pass renamed
that nothing renames any more (a removed global prefix, version or
RouterModule entry) gets the name its file gives it back, so a sync
converges with a fresh index; before, a removed RouterModule entry left
the old name, as colby's sync does. The decorator regexes are compiled
once, since the pass now scans controller files on every sync.

Goldens: servers' NestJS route becomes `GET /api/v1/users/:id` (log row
in docs/equivalence.md). Precision: express-medium and typescript-large
identical; this repository renames that route and drops the PHP
`Controller` guess; nestjs/nest's samples and specs move 43 provider
references from another app's class to the spec's own and resolve 14
more. Its 302 routes without a bootstrap of their own take the `/api` of
the one root-level e2e spec that sets one, by upstream's bootstrapFor.
A sync of typescript-large declaring @nestjs/core takes 2.8% longer
(median of three).

The sync matrix gains four NestJS cases and checks node names. The
Express and cross-tier halves of upstream's test come with W7-19a and
W7-20.
…component

Nuxt's file routes move from the Vue resolver to their own `nuxt`
resolver (upstream #2130), detected by a `nuxt`, `nuxt3` or `@nuxt/kit`
dependency or a `nuxt.config.*` file, and gated to the apps whose
nearest manifest declares one (#2129). A plain Vue app keeps its views
in a `pages/` folder just as often, and those are components a router
config names, not addresses: halo's console no longer makes a route of
each of them. Every path gets a leading `/` before the `pages/`,
`server/api/` and `middleware/` searches, so a Nuxt app at the
repository root finds its endpoints and middleware as a nested one does;
a top-level `pages/index.vue` is `/`, and a `server/api/` file takes a
page's param syntax (`[id]` -> `:id`, `[...slug]` -> `*slug`; `index`
is the folder's path, `/api` at the top).

A page route `calls` the component its own file is (#2267, new
`frameworks/page_component.rs`): the route says so by the file's
basename, and the resolver lands it on that file's component only,
never on a same-named one elsewhere (every `index.vue` is a component
named `index`). The viewer's routes list counts a component as a
route's handler, so a Nuxt page is listed with the component that
serves it.

Goldens: routers' Nuxt index route becomes `/` (its id moves) and its
two pages gain a `framework` edge each (log row in docs/equivalence.md).
Precision: express-medium and typescript-large identical; elk's 59 pages
each reach their own component, its root route is `/` and its four
`server/api/` routes appear; halo's console loses 12 routes that were
components.

The sync matrix gains three Nuxt cases: a `nuxt.config.ts` appearing,
an app's manifest coming to declare Nuxt, and a page's template edit.

The Astro half of #2267 comes with W7-19a, and #2130's Vue Router
admin-template half with W7-11. Upstream's later change to vue.ts
(#2633, 986de95c: `@/`/`~/` imports left to the import resolver) is
left for the next round.
Explore opens with the call path among the symbols the query names
(upstream's Flow section, #365): when two or more named callables are
connected by a chain of three or more, one numbered line per symbol and
one `↓` line per hop come before the header. The search is
named_symbol_flow's, the one the viewer's Flow rides, so of two equally
long routes the Flow takes the one through the symbols the query names
(#2453's explore half).

A hop names the conditions its call runs under (#1655). The new
codegraph-graph branch_guards module reads them from the caller's
current source with the extractor's grammars: the if/else and ternary
arms, switch cases, `&&` / `||` short circuits and catch blocks around
the call site up to the enclosing function, and the early exits before
it, negated, for JavaScript, TypeScript, Swift, Python, Java, Kotlin,
C#, Go, C, C++ and Objective-C callers: `↓ calls (when !busy && ready)`.
A caller file that changed since it was indexed, or one above 256 KiB,
gets no condition rather than one read at a moved line. Upstream's rules
read fwcd's Kotlin grammar and an older Go grammar; this port reads
kotlin-ng's tree (arms without control_structure_body,
return_expression, a bare break or continue as an identifier) and
tree-sitter-go 0.25's statement_list for the same labels, and passes
every guard label of upstream's branch-guards tests. codegraph-graph now
depends on codegraph-extract for the grammars.

A synthesized hop reads as the dynamic dispatch it is, in the Flow and
in the codegraph_node trail: `dynamic: interface → impl
@src/pdf-exporter.ts:5` (new synthesized_hop module, upstream's
synthesized-hop.ts at cd97bb37, #2428). The index has no synthesized
edges until the synthesis stage (W7-14), so only the engine test shows
the tag for now.

Not in this commit: the dynamic-dispatch links among the named symbols
(W7-26), boundary and polymorphic-dispatch announcements for a flow that
does not connect (the port keeps its boundary scan over the explore
seeds), and the spine's weight in file ranking and body windows (W7-25).
Upstream's interface cases of #2453 need interface-impl edges and come
with W7-14. Upstream rows left for the next round: #2750 (f5dfa21f,
PORT, named-symbol-flow.ts), #2769's branch-guards hunk (6bd217a2,
PARTIAL, the Steps status reader this commit does not port), and the
explore rows #2783 (1890b10c, PARTIAL), #2789 (214ef50e, PORT) and #2557
(5da4a41d, PARTIAL).

Goldens and the MCP fixtures are unchanged: the mini fixture's query
`Counter add runDemo` connects no chain of three, because runDemo calls
add directly and the walk reaches it first.
A `NestFactory.create` in a test file (an e2e spec) with no `src/`
segment above it now belongs to the directory above its test folder
(`integration/security/` for `integration/security/e2e/csrf.spec.ts`),
or to the directory holding it. Within one app root, the bootstraps of
the app's entry points decide over a test's: an e2e spec's
`setGlobalPrefix('api')` does not rename the routes `src/main.ts`
serves.

W7-02 ported upstream b635dd46's appRootOf and bootstrapFor as they
are. They put every such spec at the repository root and prefer the
bootstrap that configures the app, so on nestjs/nest one integration
app's spec gave its `/api` to 306 routes of ten other integration apps
and packages/core's specs. With this change only
integration/security's own routes and sample/24's keep `/api`.
express-medium and typescript-large are identical, and no golden
changes. This is a deliberate difference from upstream (KEEP-RUST,
recorded in KNOWN_DIFFS.md). It answers the W7a sub-wave gate's first
round.
W7-04 (9ef9f69) names the resolver on the edges a framework resolution
draws (`metadata.framework`, upstream #2159) without adding a sync case
of its own. The plan requires one for every commit that changes
crates/codegraph-resolve/src.

The matrix harness gains `edge_metadata_after`, which requires an edge
of the fresh index to hold a value under a metadata key. Each sync is
already compared with the fresh index by every metadata key. Two cases
use it:

- tauri_command_body_edit_keeps_the_invoke_edges_resolver_name: an edit
  to a Tauri command's body re-resolves the TypeScript `invoke('greet')`
  at its site, and the edge keeps `framework: "tauri"`.
- tsx_framework_edge_keeps_its_resolvers_name: a `.tsx` file is
  re-extracted, and the React-resolved edge to the function a component
  value wraps keeps `framework: "react"`.

Both cases fail if W7-04's naming is removed (the fresh index lacks the
key). They also fail if the incremental resolution drops the name (the
sync differs from the fresh index). Only test files change.

This branch has not been deployed

No deployments
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.

1 participant