```
Title: AsyncFile.handler(null) (and similar null-handler setters) throws IllegalStateException after close

Steps to reproduce:
1. Open an AsyncFile (e.g., via vertx.fileSystem().open(path, options)).
2. Perform some reads/writes, then call close().
3. After closing, call asyncFile.handler(null), asyncFile.endHandler(null),
   asyncFile.exceptionHandler(null), or asyncFile.drainHandler(null).

Observed behavior:
Each of those calls throws an IllegalStateException (something like "File handle is closed").

Expected behavior:
Setting a handler to null should be allowed even after the file is closed.
It should be a no-op that simply removes the handler.
This would match the common cleanup pattern where, after closing a resource,
you null out handler references to avoid lingering callbacks—regardless of
whether the underlying handle is already closed.

Impact:
Currently, code that unconditionally sets handlers to null after closing must
guard every call behind a closed-state check, which is verbose and fragile.
Allowing null handlers on a closed AsyncFile would make resource cleanup simpler
and safer without weakening the invariant that a non-null handler cannot be
installed on a closed file.
```

Let null handlers to be set on a closed AsyncFile.


**Implementation request:**

Add `closeStatusCode()` and `closeReason()` methods to `WebSocketBase` to expose the status code and reason sent by the remote endpoint in a WebSocket close frame.

**Behavior requirements:**

- The two new methods are available on the `WebSocketBase` interface (and therefore on all WebSocket types such as server-side `ServerWebSocket` and client-side `WebSocket`).
- They return the status code (`Short`) and reason (`String`) from the **received** close frame, i.e., when the remote peer initiates the close and sends a close frame with these values.
- They must return `null` when the close is initiated locally (without a close frame from the remote side) or when the connection drops without a proper WebSocket close handshake.
- The values must be set and accessible **before** the `closeHandler` callback is invoked, so that user code inside the close handler can inspect the remote close details.
- Update the Javadoc of `WebSocketBase.closeHandler` to note that after the close handler is called, `closeStatusCode()` and `closeReason()` return the remote close information (if any).

**Non-obvious edge cases:**

- The existing internal close-frame processing already parses the close code and reason from incoming `CLOSE` frames. The new methods should simply expose that information after the `CLOSE` frame is handled, without disrupting existing frame-handling or close-notification logic.
- The values must be thread-safe (the existing `conn` monitor can be reused for access).
- The methods should not impact the serialized form or the polyglot code-generation annotations present on `WebSocketBase`.

Make available on WebSocketBase the close status code and reason - see #3047


**Ticket: Add `execute(T, Handler<T>)` to `ContextInternal` – execute a task on a context from any thread**

### Motivation
There is currently no public API on `ContextInternal` that lets you run a handler on a specific context from an arbitrary calling thread or context.
- `runOnContext(Handler<Void>)` accepts no argument.
- `executeFromIO(T, Handler<T>)` is designed to be called only from the event-loop thread that owns the context.

We need a general-purpose method that works from anywhere: from any thread, from another event-loop context, or from a worker context.

### Desired behavior
Add a new method to `ContextInternal`:

```java
<T> void execute(T value, Handler<T> task);
```

**Contract:**
- The `task` handler must eventually run on the target context (event-loop thread for an event-loop context, or a worker-pool thread for a worker context).
- When the task runs, `Vertx.currentContext()` must return the target context.
- If the caller is already executing on the target context’s thread (same thread for worker contexts, same event loop for event-loop contexts), the task may be executed immediately, preserving thread-locals where possible.
- Otherwise the task must be scheduled asynchronously on the correct thread.
- Uncaught exceptions from the task must be reported to the context’s exception handler.
- Duplicated contexts (created e.g. by verticle fan-out) must delegate to the original context’s implementation.

**Affected context types:**
- Event-loop contexts (`EventLoopContext`)
- Worker contexts (`WorkerContext`)
- Benchmark context (`BenchmarkContext`) – must compile; a minimal implementation (e.g., `UnsupportedOperationException`) is acceptable.

### Implementation notes
- The internal `execute` method currently used by `executeFromIO` shares the same signature. This will clash with the new public method. Please rename or reorganize that internal dispatch path so the new public `execute` is the canonical entry point, while `executeFromIO` retains its existing contract (caller must be on the owning event loop).
- Existing callers like `runOnContext` and `executeFromIO` must continue to work exactly as before.
- The new method should be robust against the context being shut down (similar to the safety in `runOnContext`).

### Acceptance criteria
- The new method is callable from any thread/context and delivers the task to the target context.
- Event-loop context: the task executes on the event loop.
- Worker context: the task executes on a worker-pool thread.
- Context is correctly set inside the task.
- Exceptions are routed to the exception handler.
- Duplicated contexts work transparently.

Add an execute(T,Handler<T>) method on ContextInternal to execute a context task from anywhere


The `FileSystem.readFile` implementation currently reads the entire file via `Files.readAllBytes()`, then wraps the resulting `byte[]` in a `Buffer`. This causes an extra allocation and copy of the file data.

**Request:**
Improve performance by reading directly into the Buffer’s internal Netty `ByteBuf` using a `FileChannel`, avoiding the intermediate `byte[]` copy. The Buffer should be pre‑allocated with the known file size upfront.
For files larger than `Integer.MAX_VALUE` bytes, throw an `OutOfMemoryError` (matching the behavior of `Files.readAllLines` on such oversized files).

Avoid extra byte copy inside FileSystemImpl.readFileInternal (#5730)


**Title:** JsonArray/JsonObject hashCode violates contract with equals for numeric coercion

**Description:**

`JsonObject` and `JsonArray` override `equals()` to perform numeric coercion. For example, a `JsonObject` containing the integer `4` and one containing the double `4.0` are considered equal. This is necessary because JSON does not distinguish between integer and floating-point representations of the same numeric value.

However, neither class provides a matching `hashCode()` implementation. Both delegate to the backing `java.util.Map` or `java.util.List`, which computes hash codes using the standard JVM object identity for boxed numbers. Since `Integer(4)` and `Double(4.0)` have different hash codes, two logically equal `JsonObject`/`JsonArray` instances can produce different hash codes.

**Reproduction / Impact:**

```java
JsonObject a = new JsonObject().put("x", 4);      // contains Integer
JsonObject b = new JsonObject().put("x", 4.0);    // contains Double

assert a.equals(b);               // passes
assert a.hashCode() == b.hashCode(); // fails → hash-based collections break
```

This violation of the `hashCode` contract causes incorrect behavior when instances are used in `HashSet`, `HashMap`, or any hash-based data structure (duplicates, lookup failures, etc.). The problem applies recursively to nested `JsonObject`/`JsonArray` values because `equals` recurses but `hashCode` does not.

Additionally, the numeric coercion logic used by `equals` currently lives only inside `JsonObject` and is imported by `JsonArray` via a static import. This makes it harder to reuse the same rules for a consistent `hashCode`.

**Expected behavior:**

- `JsonObject` and `JsonArray` must implement `hashCode()` so that **equal objects always have equal hash codes**, including when Number values of different types are equivalent under the coercion rules.
- For `Number` values, the hash code must be computed in a way that matches the equality logic (e.g., using the double value or another strategy that yields the same result for `4` and `4.0`).
- For non-`Number` values, the standard `hashCode()` of the value should be used.
- `null` values must be handled consistently and contribute a well-defined hash (e.g., `0`).
- The computation must recurse into nested `JsonObject`/`JsonArray` so that deeply equal structures produce the same hash code.
- The number coercion logic should be shared between `equals` and `hashCode` to avoid divergence, ideally in a common place accessible to both `JsonObject` and `JsonArray`.

This fix should make `JsonObject` and `JsonArray` safe to use as keys in hash-based collections and remove the current contract violation.

Provide a coherent implementation of hashCode for JsonObject/JsonArray with respect to equals.


Make the private JSON token-parsing methods (`parseAny`, `parseObject`, `parseArray`) in `JacksonCodec` public.
These methods should allow callers to parse a JSON value, object, or array from a Jackson `JsonParser` that has been advanced to the beginning of that structure. The methods must consume the complete value and leave the parser positioned after the end of the parsed structure, so the caller can continue reading subsequent tokens without losing state. Validate that the current parser token matches the expected type (e.g., `START_OBJECT` for `parseObject`) and throw a suitable error otherwise.

Expose JacksonCodec private parse methods.


```
Refactor OutboundMessageChannel to improve safety during reentrant write/drain scenarios and to defer drained notifications.

Current behavior:
- When the event-loop thread adds a message that triggers a required drain, the drain is performed inline, which can lead to reentrant drain operations.
- The "drained" callback (`afterDrain`) is invoked synchronously during the drain, which can cause stack overflows or unintended reentrancy if the callback writes again or modifies internal state.
- The `drain()` method is public and directly called by channels when writability changes; it unconditionally drains if the overflow flag is set, but there is no guard against concurrent drains.
- The channel does not support configurable water marks for the underlying message queue.

Desired behavior:
- Use a dedicated `draining` flag (in event-loop state) to prevent reentrant drain execution. When a write from the event-loop thread finds a drain is required, the drain should be executed only if not already draining.
- Invoke the drained callback asynchronously on the next event-loop tick, so that any re-processing triggered by the callback (e.g., resuming writes) cannot interleave with the current drain operation.
- Introduce a public `tryDrain()` method that checks the `overflow` flag and, if set, resets it and performs the drain. Callers that respond to improved writability (e.g., `VertxHttp2Stream.onWritabilityChanged`, `VertxConnection.channelWritabilityChanged`) must adopt `tryDrain()`.
- Add a constructor overload that accepts `lowWaterMark` and `highWaterMark` parameters, forwarding them to the underlying `MessageChannel.MpSc`.
- Ensure proper cleanup when the channel is closed while a drain is in progress: message disposal should be deferred until the ongoing drain finishes.
- Keep the internal naming consistent: rename `disposeMessage` to `handleDispose` and `afterDrain` to `handleDrained` (the deferred callback).

These changes must pass the existing `OutboundMessageChannelTest` suite and also cover additional reentrant drain scenarios, including:
- reentrant overflow triggering a nested write during consumption
- tryDrain from within a message consumer
- writing from the drained callback itself
- draining after an async close schedule.
```


**Title:** `SocketAddress` and `HostAndPort` should be `@DataObject` with consistent JSON round-tripping

`SocketAddress` and `HostAndPort` are currently annotated `@VertxGen`, but they are almost always used as data objects (passed in options classes, serialised/deserialised from JSON). This causes two concrete problems:

1. **Missing JSON conversion for `ConnectOptions.remoteAddress`** – the manually-written `ConnectOptionsConverter` does not handle the `remoteAddress` field at all, so `SocketAddress` values are silently lost during JSON conversion.
2. **Duplicated, inconsistent JSON logic in `RequestOptions`** – `RequestOptions` manually interprets the JSON representation of a `SocketAddress` instead of delegating to the type itself; this duplicates the domain-socket vs. inet-socket branching and is likely to diverge.

We should treat `SocketAddress` and `HostAndPort` as data objects:
- Change the annotation of `Address`, `SocketAddress`, and `HostAndPort` from `@VertxGen` to `@DataObject`.
- Give `SocketAddress` and `HostAndPort` standard `fromJson(JsonObject)` / `toJson()` methods so that they own their JSON representation.

**Expected JSON representations and invariants:**

- **`SocketAddress`**:
  - Inet address: `{"host": "<host>", "port": <port>}`. A negative port value means a **shared random port** bound to the given host (the actual ID is the absolute value).
  - Domain socket: `{"path": "<path>"}`.
  - `toJson()` must throw `IllegalStateException` for any other kind (though none exist today).
  - `fromJson(null)` or a JSON that cannot be decoded returns `null`.
- **`HostAndPort`**:
  - `{"host": "<host>"}` when the port is absent or ≤ 0.
  - `{"host": "<host>", "port": <port>}` when the port is positive.

**Callers to update:**

- `RequestOptions` should use `SocketAddress.fromJson` / `toJson` instead of its current ad‑hoc `server` handling.
- `ConnectOptionsConverter` should be updated to convert `remoteAddress` using `SocketAddress.fromJson` / `toJson`. (The converter is maintained manually; regenerating it is acceptable as long as it respects the existing conventions.)

No other user-visible API changes. The existing tests that deal with `SocketAddress` construction should pass; also test that JSON round‑trips correctly for inet addresses (including shared‑random ports) and domain sockets, and for `HostAndPort` with and without a port.

SocketAddress and HostAndPort are actually data objects and shall rather annotated with @DataObject than @VertxGen


Title: Plus sign (`+`) in resource filenames decoded to space, causing file lookup failures

Description:
When using Vert.x's file resolution (e.g., through `FileResolver`, verticle compilation, or package scanning), filenames or paths containing a literal `+` character are incorrectly converted to spaces. This leads to `FileNotFoundException` or incorrect path resolution, because `java.net.URLDecoder` treats `+` as a space (the `application/x-www-form-urlencoded` convention), but file paths are not query strings.

For example, a resource named `this+that` inside a JAR or on the classpath cannot be loaded. The resolved path becomes `this that` instead of preserving `this+that`.

Expected behavior:
Plus signs in filesystem paths should be preserved as literal `+` characters. Percent-encoded sequences (e.g., `%20`) should still be decoded to the corresponding characters, but the `+` character itself should not be transformed to a space.

This affects all code paths that currently use `java.net.URLDecoder.decode()` to interpret URL file paths from classpath resources, JAR entries, and source file locations. The decode logic should be replaced with an alternative that does not misinterpret `+`. It may be desirable to allow the caller to explicitly control whether `+` is treated as a space, since some internal use cases might still need that behaviour (e.g., query parameters), but for file resolution the default should be to keep `+` unchanged.

Context:
- File resolution happens in several places: `FileResolver` (for classpath/JAR resources), `CompilingClassLoader` (for `.java` source compilation), and `PackageHelper` (for package content scanning).
- The core issue is that `java.net.URLDecoder` implements the `application/x-www-form-urlencoded` decoding, which is inappropriate for path segments decoded per RFC 3986.

A correct fix should ensure that any new or existing URI/URL decoding helper preserves `+` as a literal character when requested, and that all file-path resolution sites bypass the `+`-to-space conversion.

Fixes #2619: properly handle plus signs when resolving paths (#2623)


We should simplify the `deleteRecursive` and `deleteRecursiveBlocking` methods on `FileSystem` by removing their `recursive` parameter. The method name already makes it clear that the operation is recursive; having a `recursive` parameter that can turn off recursion is redundant and confusing. For non-recursive deletion the existing `delete` method should be used directly.

- Remove the `recursive` parameter from `FileSystem.deleteRecursive` and `FileSystem.deleteRecursiveBlocking`.
- Update the implementation in `FileSystemImpl` so that these methods always perform a recursive delete (i.e., pass `true` for the internal recursive flag).
- Adjust every call site inside the repository that passes a value for that parameter; in particular make sure the internal file-system tests are adapted to the new signatures and that all existing test scenarios continue to be covered (recursive delete tests should go through `deleteRecursive`, non-recursive delete tests through `delete`).

Remove FileSystem recursive deletion that uses a recursive parameter: instead deleteRecursive or delete should be used


**Request: Complete the Jackson v3 `JsonCodec` implementation to match the v2 capabilities**

The Jackson v3 codec (`io.vertx.core.json.jackson.v3.JacksonCodec`) is partially implemented and currently throws `UnsupportedOperationException` for several core operations. We need it to fully implement the `JsonCodec` contract:

* **Buffer-based decoding and encoding**
  `fromBuffer` must accept a Vert.x `Buffer` containing JSON and return the appropriate Java object.
  `toBuffer` must serialize any JSON-compatible object into a `Buffer`, honoring the `pretty` flag (when `true`, output should include whitespace/indentation).

* **Pretty-printing in `toBuffer`**
  The codec must produce human-readable JSON when `pretty` is `true`, using a suitable pretty-printer (as the v2 codec already does for `toString` and `toBuffer`).

* **Error handling**
  Jackson v3 specific exceptions (e.g., `JacksonException`) encountered during parsing must be caught and wrapped into `DecodeException`, preserving the original message.

* **Jackson factory configuration**
  The `JsonFactory` must respect the same system-property overrides for stream read constraints that the v2 codec supports: `vertx.json.jackson.maxNestingDepth`, `vertx.json.jackson.maxDocumentLength`, `vertx.json.jackson.maxNumberLength`, `vertx.json.jackson.maxStringLength`, `vertx.json.jackson.maxNameLength`, and `vertx.json.jackson.maxTokenCount`. Invalid property values should be logged as a warning and the factory should fall back to Jackson defaults.
  Non-standard JSON features, such as Java-style comments, must be allowed (as the v2 codec permits).

* **Test suites should pass**
  The v3-specific test classes inheriting from `JsonArrayTest`, `JsonObjectTest`, and `JsonCodecTest` should no longer skip relevant test cases. In particular, `testClusterSerializable` and `testCreateFromBuffer` for both `JsonArrayTest` and `JsonObjectTest` must execute successfully. A new `JacksonCodecTest` that exercises all of `JsonCodecTest` with the v3 codec must be added and pass.

The goal is to make the v3 codec a drop-in replacement for the existing v2 codec, with parity in functionality and configuration.

Complete implementation of jackson v3 codec


**Async JSON parser fails on integer values outside the signed long range**

When parsing a JSON stream using the asynchronous `JsonParser` (e.g., via `io.vertx.core.parsetools.JsonParser`), a numeric token that contains an integer literal too large to fit in a Java `long` (for example, `18446744073709551615`) causes a `DecodeException` to be thrown. The parser should handle such values seamlessly.

**Acceptance Criteria**

* Given a JSON input containing an integer literal that exceeds `Long.MAX_VALUE` (signed 64-bit range), the parser must emit a `JsonEvent` with `type()` indicating a value and `isNumber()` returning `true`.
* The `event.value()` for such a large integer must be a `java.math.BigInteger` whose numeric value equals the input.
* The event must report the correct numeric value through the standard accessors (`integerValue`, `longValue`, `floatValue`, `doubleValue`) without throwing exceptions (truncation for `int`/`long` is acceptable, following Java semantics).
* The event must *not* be a string, boolean, null, array, or object.
* **Backward compatibility:** Integers that do fit in a signed long (e.g., `567`) must continue to be represented as `Long` instances via `value()`, exactly as they were before, so that existing consumers relying on the previous `Long` representation are not broken.
* The existing behavior for all other JSON value types (strings, booleans, null, objects, arrays, floats/doubles) must remain unchanged.

Async JSON parser should handle large integer (literaly speaking) number representations.


We’re looking for a small generics improvement to the `Context.getLocal` method that accepts a `Supplier`. Currently the supplier type is invariant, forcing callers to provide exactly `T` even when a subtype would be safe.

Acceptance criteria:

- The `Context.getLocal(ContextKey<T> key, Supplier<T> supplier)` method (declared in `io.vertx.core.Context`) must accept a `Supplier` that produces any value assignable to `T`, using a bounded wildcard. This is a source-compatible change that widens what callers can pass.
- The same change must be applied consistently to the implementation(s) in `io.vertx.core.impl` and to the test helper that implements `ContextInternal` (the method is already overridden in `FakeContext`). All overrides must match the new signature.
- The method is currently annotated with `@GenIgnore(GenIgnore.PERMITTED_TYPE)`. Because the widened signature uses a wildcard, the code generator may no longer be able to handle it under the `PERMITTED_TYPE` mode. The annotation must be changed to plain `@GenIgnore` so the method is completely ignored by the generator and does not trigger processing errors.
- The default `removeLocal` method and other `@GenIgnore`-annotated local-context methods (`putLocal`, `getLocal(key)` without supplier) should also be adjusted to plain `@GenIgnore` if the same problem applies, to keep the generator ignore-level consistent and avoid surprises with future signature changes.


**Cluster selector: reduce boxing/allocations when computing node weights**

The `SelectorEntry.data()` method computes a weight map from the list of node IDs every time a new cluster view arrives.
Currently it uses `Integer` values and `Map.merge(…, Math::addExact)`, which creates a new boxed `Integer` for each increment.
The `isEvenlyDistributed` check then streams the weight values and calls `distinct().count()`, which is unnecessarily expensive and does not short‑circuit.

**Request:**
Replace the `Integer` weight with a lightweight mutable counter so the compute step avoids boxing and allocations.
Rewrite the even‑distribution check to iterate once over the weight values, comparing each against the first value (or comparing consecutive values) and returning `false` as soon as a mismatch is found.

**Constraints:**
- The `WeightedRoundRobinSelector` consumes the weight map and sorts entries by weight; the new weight type must still be `Comparable` so that `Map.Entry.comparingByValue()` works.
- All changes should be internal to the `io.vertx.core.spi.cluster.impl.selector` package; no public API changes.
- Existing tests in `WeightedRoundRobinSelectorTest` must continue to pass (they will need trivial updates to match the new weight type).

Minimize allocation when receiving new cluster view


We need to relocate and expose the classpath file cache directory. Currently, the file resolver caches files resolved from the classpath under `.vertx/file-cache-*` in the process working directory. That clutters application directories and can fail when the working directory is not writable. Change the default cache location to use the system temporary directory (`java.io.tmpdir`), with a `vertx-cache` subdirectory, so that by default on Linux it lives under `/tmp/vertx-cache/file-cache-*`. If the temporary directory property is absent, fall back to the current directory.

Keep the existing `vertx.cacheDirBase` system property working as a global override for the cache base (its value should be used directly, not in combination with the temp directory). Additionally, expose the cache base directory as a configurable property in `FileSystemOptions`, so that it can be set programmatically per-resolver, with the same default semantics.


**Title:** `OutboundMessageQueue` drain executes after the queue is closed

**Description**
When an `OutboundMessageQueue` is closed, any drain operation that was already scheduled (e.g. because the queue had become full) can still execute. Since the queue has been cleared and the close state has been entered, the drain finds no elements and the queue no longer expects a drain. This can cause unexpected callbacks or errors such as attempting to write into a drained-but-closed queue.

**Steps to reproduce** (conceptually)
1. Fill an `OutboundMessageQueue` from a thread outside the event loop until it returns `false` (i.e., it becomes full and a drain is scheduled).
2. On the event loop, close the queue before the scheduled drain runs.
3. The pending drain fires after the close and proceeds to call `startDraining()` and attempt to process elements, even though the queue is closed.

**Expected behavior**
After the queue is closed, any pending drain operation should be skipped or become a no-op. A drain that starts while (or after) the queue is in the closed state must not invoke `startDraining()` and must not attempt to move elements.

The outbound message queue should not try to drain its write queue after it has been closed.


```
Title: Optimize InboundReadQueue for event-loop contexts

Currently `InboundReadQueue` uses atomic operations (`AtomicLong`) and a Netty Single‑Producer Single‑Consumer (SPSC) queue to coordinate between the producer and consumer. In Vert.x event‑loop contexts all work runs on the same thread, so the atomic/volatile overhead from the SPSC variant is unnecessary.

We need a variant of `InboundReadQueue` that is safe and efficient when the producer and consumer always execute on the same thread. This variant must:
- use a plain queue (e.g. `ArrayDeque`) instead of an SPSC queue,
- replace atomic updates with plain field accesses for the internal work‑in‑progress counter,
- preserve the exact public contract of `InboundReadQueue` (add/drain semantics, high‑/low‑water marks, `QUEUE_UNWRITABLE_MASK`, `DRAIN_REQUIRED_MASK`, `drainResult`, etc.).

`InboundMessageQueue` should automatically select this single‑threaded variant when its `ContextInternal` reports `ThreadingModel.EVENT_LOOP`. For all other threading models the existing SPSC implementation must continue to be used. No public API changes are allowed; the selection must be transparent to callers.

Existing tests must continue to pass without modification (except where they directly construct `InboundReadQueue` instances – the test suite already validates both implementations).
```

InboundReadQueue implementation for event-loop


We should simplify the `ContextImpl` constructor so that it no longer implicitly picks an event loop. The base class currently provides a constructor overload that does not accept an `EventLoop`; it uses a private helper to fetch one from the vertx instance. This indirection makes it hard to reason about which event loop a context is bound to and complicates the code unnecessarily.

**Desired behavior:**
- Remove the constructor overload and the implicit event-loop selection logic.
- The remaining `ContextImpl` constructor must accept an `EventLoop` parameter explicitly.
- Update all call sites so they pass an `EventLoop` directly. For `WorkerContext`, the event loop should be obtained from the event loop group (e.g., `vertx.getEventLoopGroup().next()`) rather than relying on the removed default.
- `VertxImpl.createEventLoopContext` should similarly pick an event loop from the group and pass it to the `EventLoopContext` constructor.
- The change must preserve the existing behavior: every context still uses an event loop from the group as before, but the choice is now explicit and made at the call site instead of being hidden inside the base class.


**Title:** Add terminal `onComplete(Handler<T>, Handler<Throwable>)` overload to `Future`

**Description**
The `Future` interface currently offers a terminal `onComplete(Handler<AsyncResult<T>>)` and the convenience methods `onSuccess` and `onFailure`. Users who want to handle both success and failure often end up checking `ar.succeeded()`/`ar.failed()` inside a single handler. We should provide a new overload:

```java
Future<T> onComplete(Handler<T> successHandler, Handler<Throwable> failureHandler);
```

This operation is terminal, and it dispatches directly to the appropriate handler based on the future’s outcome.

**Behaviour & invariants**

- If the future has succeeded, exactly `successHandler.handle(value)` is called (provided the handler is non‑null).
- If the future has failed, exactly `failureHandler.handle(cause)` is called (provided the handler is non‑null).
- If a handler is `null` it is silently ignored – no `NullPointerException` must be thrown.
- The method must return `this` for fluent chaining.
- **Exception safety:** if either handler throws an exception, the behaviour must match what the existing listeners do: if a Vert.x context is available (`context` field in the implementation), the exception must be reported to that context via `context.reportException(t)`; otherwise the exception must be rethrown directly. This is critical so that errors in user code do not get silently swallowed.
- The existing `onSuccess` and `onFailure` default methods should be re‑implemented to delegate to this new overload, reducing duplication.

**Implementation notes**

- Add a `default` method body in the `Future` interface, delegating to the existing `onComplete(Handler<AsyncResult<T>>)`. This gives an immediate, correct fallback for any custom future implementations.
- In the concrete future implementation (`FutureImpl`), override the new method with an optimised version that registers a `Listener` directly, without wrapping the two handlers inside an `AsyncResult` handler. This avoids unnecessary object allocations and should follow the same pattern used when registering other terminal listeners (see how `Listener` is used elsewhere in that class).
- The optimised override must still handle null handlers and must apply the same exception‑reporting logic described above.

**Testing**
Add coverage in the existing `FutureTest` (methods `testSuccessNotification` and `testFailureNotification` are natural places) that exercises the new overload for both success and failure paths, including cases where one of the handlers is `null`. Ensure the expected number of completions is adjusted accordingly.


The new experimental React Flare keyboard responder (`useKeyboard`) does not support stopping propagation of keyboard events to parent responders. In a nested component tree where both an inner and an outer component register `onKeyDown` or `onKeyUp` handlers, both handlers are always invoked for the same event, regardless of whether the inner handler wants to prevent further handling.

**Expected behavior:**
Keyboard event handlers (`onKeyDown` / `onKeyUp`) should be able to control whether the event propagates to parent keyboard responders. Returning a boolean from the handler—specifically `false`—should stop propagation, mimicking the effect of `stopPropagation` in the DOM event system. If the handler does not return a value (or returns `true`), propagation should continue as before.

**Current behavior:**
All responder handlers in the hierarchy are called. There is no mechanism to prevent outer handlers from executing once the event has been dispatched.

**Impact:**
This prevents common patterns like trapping keyboard focus inside a modal, dropdown, or inline editor. Without propagation control, developers must resort to fragile workarounds (e.g., manual state sharing) to suppress outer handlers, which is error-prone and contradicts React's composable model.

The fix should:
- Update the keyboard responder’s `dispatchKeyboardEvent` to read the return value of the user-provided event listener.
- If the listener returns `false`, call a method on the responder context (e.g., `context.continuePropagation()`) that stops the event from being sent to the next responder.
- Ensure the `dispatchEvent` pipeline in `DOMEventResponderSystem` returns the listener’s value and respects the propagation flag when iterating through responder instances.

[react-events] Keyboard responder propagation handling (#16657)


## Bug Report: ErrorBoundary rethrow drops component stack information

**Title:** Component stack is lost when an Error Boundary rethrows an error to a higher boundary

**Severity:** High – undermines ErrorBoundary composability and makes debugging deeply nested error-handling trees extremely difficult.

**React version:** (any recent version before the fix)

### Steps to reproduce:
1. Create a component tree like this:
   - A `CatchingBoundary` (top-level error boundary)
     - A `Foo` component
       - A `RethrowingBoundary` (error boundary that catches but rethrows)
         - A `Bar` component
           - A `SomethingThatErrors` component that throws an Error.
2. In `RethrowingBoundary.getDerivedStateFromError`, simply `throw error;` again.
3. In `CatchingBoundary.componentDidCatch`, inspect `info.componentStack`.

### Expected behavior:
The `componentStack` reported to the top-level `CatchingBoundary` should include the entire chain from the source (`SomethingThatErrors`) all the way up to `CatchingBoundary`, preserving the original stack where the error was first thrown.

### Actual behavior:
The component stack only shows the path from the **rethrowing boundary** upward (`RethrowingBoundary → Foo → CatchingBoundary`), completely omitting `SomethingThatErrors` and `Bar`. This breaks the illusion that ErrorBoundaries are transparent when they rethrow. Developers relying on composable boundary hierarchies get misleading stack traces that make it impossible to identify the actual source of the error.

### Impact:
- ErrorBoundaries are not truly composable: any intermediate boundary that decides not to handle an error destroys valuable debugging context.
- Libraries or higher-order patterns that use intermediate boundaries to augment or conditionally suppress errors lose the original error site information.
- Debugging production errors that happen in deeply nested, error-handling tree structures becomes impractical.

### Desired solution:
When an error is caught by an ErrorBoundary and then rethrown, the React runtime should preserve the *original* component stack at the point the error was first thrown, and make it available to a higher boundary that eventually handles the error. Conceptually, the stack should be "stashed" alongside the thrown value so that any subsequent rethrow can reuse it.

### Edge cases / constraints:
- The solution must work with all object values thrown as errors (`Error` instances, custom object throw values). For primitives (strings, numbers) it is acceptable to fall back to a stack recomputed from the current boundary, because throwing primitives is unusual and can’t carry attached metadata.
- The behavior should be consistent whether the error originates from a synchronous render, a lazy component, or a server-side hydration error (Suspense).
- The stack must remain accurate across multiple rethrows if an error passes through several boundaries.
- The implementation must be safe with respect to memory leaks (e.g., using weak references for object values) so that error objects can be garbage collected after they are no longer needed.

stash the component stack on the thrown value and reuse (#25790)


We need to enforce that `useContext` (or any direct read of context) is forbidden inside the callbacks provided to `useMemo`, `useEffect`, `useLayoutEffect`, and the reducer/initializer of `useReducer`. This also applies to the eager state computation that occurs when dispatching an action to `useState`/`useReducer` before the next render. The goal is to prevent subtle bugs caused by reading context outside the render phase, ensuring that context values used in these callbacks are always captured during rendering and never accessed prematurely or in a stale environment.

**Acceptance Criteria**

1. **useMemo** – When a call to read context (via `ReactCurrentDispatcher.current.readContext` or a `useContext` hook) happens inside the factory function of `useMemo`, React must throw an error with a message indicating that context can only be read while React is rendering (e.g., `"Context can only be read while React is rendering"`).

2. **useEffect and useLayoutEffect** – A read of context inside the setup or cleanup function of `useEffect` / `useLayoutEffect` must throw. The error may differ (due to dispatcher being `null`), but the behavior is the same: reading context there is not allowed.

3. **useReducer** – Reading context inside a reducer function or inside the lazy initializer of `useReducer` must throw the same invariant error as in useMemo.

4. **Eager dispatch** – When a state setter from `useState` or `useReducer` is called outside of rendering, and the update is eagerly computed, any attempt to read context during that eager computation must throw the same error. This covers a class component calling a setter from a hook; the eager reducer runs synchronously but must still be forbidden from reading context.

5. **Interleaved reads** – If context has already been read successfully before entering the hook callback (e.g., before `useMemo`), reading it again inside the callback must still throw. Reading context after the callback (back in the legitimate render phase) must continue to work correctly.

6. **Render phase unaffected** – Reading context during the normal render phase (outside of these special callbacks) must remain fully functional and unchanged.

7. **Consistent invariant** – The rule “context can only be read while React is rendering” must hold uniformly across all hooks. Any attempt to read context outside the rendering cycle of a component (including inside memo/reducer/effect callbacks) should be reliably detected and prevented with a descriptive invariant.

Disallow reading context during useMemo etc (#14653)


Add a `FocusList` component to the `react-interactions/accessibility` package that enables keyboard navigation among items in a one-dimensional list using the Scope API and the `useKeyboard` responder.

Requirements:
- The component is exposed via a `createFocusList` factory (similar to `createFocusTable`) that takes a `scopeImpl` function and returns a `[List, Item]` pair.
- `List` wraps children and accepts a boolean `portrait` prop:
  - `portrait=true` → ArrowUp/ArrowDown move focus to the previous/next `Item`.
  - `portrait=false` → ArrowLeft/ArrowRight move focus to the previous/next `Item`.
- `Item` wraps each focusable child and registers a keyboard handler. When the scoped ref is `null`, the event must continue propagation without taking action (same guard recently added to `FocusTable`’s cell handler).
- Moving focus beyond the first or last item stops at the boundary; no wrapping occurs.
- The navigation uses `getChildren()` on the list scope and `indexOf` to locate the current item, then focuses the first tabbable node inside the target item via `getScopedNodes`.
- Arrow keys in the inappropriate orientation must be ignored (e.g., ArrowLeft/Right when portrait, ArrowUp/Down when landscape).

[react-interactions] Add FocusList component (#16875)


## Feature Request: Warn on variable assignments inside Hooks for `exhaustive-deps`

### Problem
Users sometimes write an assignment to an outer variable inside a `useEffect` (or other React Hook), expecting the updated value to survive across re-renders. In reality the assignment is lost on the next render unless the variable is a ref. This is a common mistake with no existing lint feedback.

### Acceptance Criteria

1. **New warning in the `exhaustive-deps` rule**
   When an assignment expression targets a variable declared outside the Hook (e.g., `value = 42` inside a `useEffect` callback), produce a distinct warning. The message must include:
   - the variable name,
   - a note that the assignment will not persist between re-renders,
   - a suggestion to either move the variable inside the Hook or to use `useRef` and update `current`.

   The warning should fire for `useEffect`, `useLayoutEffect`, `useMemo`, and `useCallback` (any “reactive hook” tracked by the rule).

2. **No warning for property assignments**
   Assignments to a property of an outer variable (e.g., `obj.foo = true`) must **not** trigger the warning. Only direct reassignment of the variable binding itself is flagged.

3. **Suppressed missing-dependency suggestions**
   When at least one stale-assignment warning is emitted for a Hook invocation, the rule must **not** report missing dependencies or offer autofixes for dependency arrays. This avoids misleading advice when the developer’s intent is unclear.

4. **Compatibility with existing `exhaustive-deps` logic**
   The existing dependency analysis (missing and unnecessary deps) must remain unchanged otherwise. Property accesses on an assigned variable should still be tracked for dependency purposes.

[ESLint] Warn against assignments from inside Hooks (#14916)


We need to deprecate using a context object directly as a consumer element (e.g., rendering `<MyContext>`). In a future major release, this pattern will no longer work; the correct pattern is to render `<MyContext.Consumer>`. Add a DEV-only warning when a context object is used as a consumer.

Additionally, warn in DEV when:
- `<Context.Consumer.Provider>` is used (correct is `<Context.Provider>`)
- `<Context.Consumer.Consumer>` is used (correct is `<Context.Consumer>`)
- `Context.Consumer.unstable_read()` is called (correct is `Context.unstable_read()`)

The `Context.Consumer` object should be a separate proxy object with a distinct `$$typeof` so that the reconciler can detect misuse without affecting PROD builds. In DEV, its `Provider`, `Consumer`, and `unstable_read` properties should delegate to the underlying context but trigger the appropriate warnings on access.

Deprecate context object as a consumer and add a warning message (#13829)


**Title:** Press responder – support `onContextMenu` and fix macOS Ctrl+click behaviour

**Context**
The Press responder currently has no way to observe or respond to the `contextmenu` event. Right‑click / keyboard‑triggered context menus on a Press target silently fire the native menu and can leave an active press stuck because the `contextmenu` event is not treated as a cancellation trigger. On macOS the standard gesture for a context menu is `Ctrl`+left‑click; today that combination still starts a regular press, which is wrong for that platform.

**What we need**

1. **New `onContextMenu` prop**
   Add a callback `onContextMenu: (e: PressEvent) => void` to the `PressProps` type. The event object should have `type: 'contextmenu'` and carry the same geometry/modifier fields as other Press events.

2. **Context menu cancels an active press**
   When a `contextmenu` native event fires on a target that is currently in the “pressed” state (`isPressed === true`):
   - Cancel the press immediately: dispatch the usual end‑of‑press lifecycle events (`pressend`, `presschange`, …), clear any active timeouts, and remove the root event listeners.
   - **Prevent the browser’s native context menu** unless the `preventDefault` prop is explicitly `false`.
     If prevented, do **not** fire the `onContextMenu` callback – the cancellation alone communicates that a context menu was requested but suppressed.
   - If `preventDefault` is `false` (caller opts into the native menu), invoke `onContextMenu` after the press has been cancelled.

3. **Context menu without an active press**
   When `contextmenu` fires but no press is active (e.g. a right‑click without a prior left‑button down), simply invoke `onContextMenu` if provided. No cancellation or prevention is necessary.

4. **macOS Ctrl+click should not start a press**
   On macOS (`navigator.platform` begins with `"Mac"`), a `pointerdown` event with `pointerType === 'mouse'`, `button === 0`, and `ctrlKey === true` must be **ignored** as a press start, exactly as we already ignore `button > 0`. This allows the subsequent `contextmenu` event to be processed cleanly without fighting an already‑active press.

**Edge cases / invariants**
- The `contextmenu` event is still considered a discrete user input; dispatching `onContextMenu` should flush discrete updates, similar to `onPress`.
- If `preventDefault` is `false` and an active press existed, the order must be: cancel the press, then call `onContextMenu`. The caller should be able to distinguish the two logical steps.
- On non‑macOS platforms, `Ctrl`+left‑click does not need special treatment (it should start a normal press) unless we later decide to make it configurable.

[Flare] Adds onContextMenu and fixes some contextmenu related issues (#15761)


**Feature Request: `React.pure` should automatically forward refs**

Currently, `React.pure` does not forward refs. If a component that uses `React.pure` needs to accept a ref, developers must nest `React.forwardRef` inside `React.pure` (or vice versa), which is confusing, verbose, and easy to get wrong. Since `pure` is intended to simplify functional component optimization, it should naturally support ref forwarding without extra wrappers.

**Desired behavior**

- When a component is created with `React.pure(render, compare?)`, it should behave like `React.forwardRef` in terms of how it receives and handles `ref`.
- The `render` function must be called with `(props, ref)` — i.e., the ref becomes the second argument.
- The component’s bail-out optimization must account for ref changes. Specifically:
  - The default shallow bail-out (or a custom `compare` function) only compares props.
  - In addition to the prop comparison, the ref is compared using strict reference equality (`===`).
  - The component should **not** bail out if the ref has changed, even if props are unchanged (or if the `compare` function returns `true`). A new ref must always cause a re-render.
  - If both the ref and props (according to the compare function) are unchanged, the component may bail out as before.
- This behavior should be identical whether the component is loaded eagerly or lazily (i.e., through `React.lazy`).

**Motivation / Use cases**

- Eliminates the need for `React.pure(React.forwardRef(render))` or similar compositions.
- Makes it straightforward to memoize components that forward refs to DOM elements or class instances, while still preventing unnecessary renders when nothing has changed.

**Non-breaking considerations**

- Existing `pure` components that only use `props` must continue to work unchanged. JavaScript functions will silently ignore the extra `ref` argument, so no changes to existing component signatures are required.
- If a developer chooses to use the new capability by adding a `ref` parameter, the component will react to ref changes automatically.

**Acceptance criteria**

1. **Ref forwarding**
   Given a pure component created with `React.pure((props, ref) => { ... })`, when it is rendered with a `ref` attribute, the second argument of the render function receives that ref.

2. **Re-rendering on ref change**
   If the parent passes a different ref instance (reference inequality) on a subsequent render, the pure component must re-render, even if the props are deeply equal.

3. **Bail-out when nothing changes**
   If both props (as determined by the custom or default compare function) and ref (using `===`) are the same as the previous render, the component must bail out (not re-render) to preserve the optimization.

4. **Interaction with custom compare**
   When a custom `compare(oldProps, newProps)` function is provided, it is still used to decide whether props changed. The ref comparison remains a separate, unconditional `===` check that takes precedence: if the ref changed, the component re-renders regardless of the `compare` result.

5. **Backward compatibility**
   A pure component that never reads the second argument (i.e., `React.pure(props => ...)`) must behave identically to the current version, except that the bail-out logic now also respects ref identity (which is `undefined` vs `undefined` and thus equal).

---

This feature would make `React.pure` a complete replacement for the common `pure(forwardRef(...))` pattern and reduce friction when using refs with optimized functional components.

React.pure automatically forwards ref (#13822)


The `no-cross-fork-imports` ESLint rule currently only inspects `ImportDeclaration` nodes. It does not flag named export declarations of the form `export { ... } from '...'` that reference a module from the wrong fork. Extend the rule so that:

- `ExportNamedDeclaration` nodes are checked in the same way as `ImportDeclaration`.
- If a source file in the old fork exports from a module whose path ends with `.new` (or `.new.js`), report an error.
- If a source file in the new fork exports from a module whose path ends with `.old` (or `.old.js`), report an error.
- The fixer should automatically replace the suffix in the module path (`.old` → `.new` and vice versa) just as it does for imports.

Cross-fork lint: Support named export declaration (#20784)


The `TabFocusController` component currently exposes an imperative handle (via `useImperativeHandle`) that provides `focusFirst`, `focusNext`, `focusPrevious`, `getNextController`, and `getPreviousController`. It also passes a `handle` prop to the underlying `TabbableScope`, and the scope stores this handle via `getHandle` on `ReactScopeMethods`. This design couples the focus logic to the component instance and requires extra indirection.

We want to simplify the API so that focus management functions are plain utilities that accept a `TabbableScope` element (obtained through a ref) directly. The component should no longer use an imperative handle, and the scope node returned by the ref should be the raw scope – not a decorated controller.

**Acceptance criteria**
- `TabFocusController`’s ref no longer exposes an object with focus methods; it exposes the underlying scope instance (as before, but without the imperative handle layer).
- The following functions are exported from the focus module and can be called with a scope element:
  - `focusFirst(scope: ReactScopeMethods): void` – moves focus to the first tabbable element in the scope.
  - `focusNext(scope: ReactScopeMethods, contain?: boolean): boolean` – moves focus to the next tabbable element, wrapping to first when `contain` is `true` or signaling that focus should leave the scope when `false`.
  - `focusPrevious(scope: ReactScopeMethods, contain?: boolean): boolean` – analogous to `focusNext` but in the opposite direction.
  - `getNextController(scope: ReactScopeMethods): ReactScopeMethods | null` – returns the next sibling scope (if any) from the root’s scope tree.
  - `getPreviousController(scope: ReactScopeMethods): ReactScopeMethods | null` – returns the previous sibling scope.
- `TabbableScope` no longer accepts a `handle` prop.
- The `ReactScopeMethods` type no longer includes a `getHandle()` method.
- The existing keyboard behavior (Tab / Shift+Tab cycling, containment when `contain` is `true`) remains identical to the previous implementation.
- The ref passed to `TabFocusController` receives the scope node, which can be directly passed to the exported utility functions.

No other public APIs or behavior should change.

[react-interactions] Refactor TabFocusController (#16768)


Support auto-dependency inference for default-imported functions

## Background

The React Compiler’s effect auto-dependency configuration (used during `@inferEffectDependencies`) allows marking certain external functions as “auto-dep aware”. When a function is recognized, an inline callback is analyzed for captured reactive values, and a dependency array is inserted as a second call argument if none is provided. This currently works only for named imports (`import { useStableEffect } from '...'`). Default imports (`import useStableEffect from '...'`) are not recognized, even if they represent the same pattern.

## Desired behavior

When the config defines an external function with `importSpecifierName: 'default'`, the compiler should detect calls to that default-imported identifier and apply the same auto-dependency inference as it does for named imports.

For example, given a config entry:

```json
{
  "function": {
    "source": "useEffectWrapper",
    "importSpecifierName": "default"
  },
  "numRequiredArgs": 1
}
```

and source code:

```ts
import useEffectWrapper from 'useEffectWrapper';

function Comp() {
  const a = 1;
  useEffectWrapper(() => {
    console.log(a);
  });
}
```

The compiler should transform the call to:

```ts
useEffectWrapper(() => { console.log(a); }, [a]);
```

## Implementation constraints

- The existing configuration mechanism (e.g., the `autodepFnConfigs` map) currently keys only on named import specifier names. For default imports the binding kind is `ImportDefault` and the local name is arbitrary. The lookup must be based on `(moduleName, 'default')`.
- The compiler already exports a `DEFAULT_EXPORT` constant from `HIR/Environment`; reuse that token as the key when indexing into per-module configuration maps for default imports.
- The same handling should apply: the function must load a global with binding kind `ImportDefault`, check the module against the auto-dep config map, and retrieve the required argument count associated with the `'default'` entry.

## Non-goals / edge cases

- This does not change how the inference itself works. It only extends recognition to default-imported identifiers.
- Only top-level call expressions of the default-imported identifier are affected (consistent with existing named import handling).
- The existing test harness fixture configuration (complex config defaults) already includes an entry for `useEffectWrapper`; the runtime environment must be able to resolve `'useEffectWrapper'` to a suitable implementation so that evaluator tests pass.

[compiler] Support default imports for autodep config (#31657)


**Title:** Suspense `suspenseCallback` that throws combined with `useEffect` causes a spurious internal error

### Description
When the experimental `enableSuspenseCallback` flag is turned on and a `<Suspense>` boundary uses `suspenseCallback` that throws, React throws the expected error from the callback. However, if any child in the suspended subtree is a function component using `useEffect`, a second, unrelated error immediately follows. The second error references something like `Cannot read property 'lastEffect' of null`, making it hard to pinpoint the real problem and potentially interfering with error boundaries.

#### Steps to reproduce
1. Enable `enableSuspenseCallback`.
2. Render a `<Suspense>` boundary with a `suspenseCallback` that throws an error.
3. Place a child component that uses `useEffect` inside the boundary (the child can be a lazy‑loaded component that suspends).
4. Observe the thrown errors.

```jsx
function Child() {
  useEffect(() => {
    // some effect
  });
  return <div>Child</div>;
}

function App() {
  return (
    <Suspense
      fallback="Loading…"
      suspenseCallback={() => {
        throw new Error('Oops!');
      }}>
      <Child />
    </Suspense>
  );
}
```

#### Observed behavior
Two errors are thrown:
- `Error: Oops!` (from `suspenseCallback`)
- `TypeError: Cannot read property 'lastEffect' of null` (or similar) from React internals

#### Expected behavior
Only the `Error: Oops!` should be thrown. The passive effect lifecycle (`useEffect`) should not crash when the parent Suspense boundary encounters an error during its callback.

### Root cause
The internal `commitPassiveHookEffects` function unconditionally attempts to iterate over a fiber’s hook update queue when committing passive effects, regardless of the fiber’s type. For a `SuspenseComponent` fiber (or any fiber that does not hold a hook queue), this leads to accessing `null` as if it were an effect list, crashing after the user-land error has already been caught.

### Suggested fix
`commitPassiveHookEffects` should only process passive effects for fibers that can actually hold hook state. Before iterating, check:
1. The fiber’s `effectTag` includes the `Passive` flag.
2. The fiber’s `tag` is one of `FunctionComponent`, `ForwardRef`, or `SimpleMemoComponent` (the three component types that support hooks).

Any other fiber types (including `SuspenseComponent`) must be skipped entirely. This ensures that unrelated internal errors do not cascade from a user error and error boundaries can work correctly.

### Impact
- Any application using `suspenseCallback` with function components that use `useEffect` can break confusingly when the callback throws.
- Error boundaries may receive the secondary error instead of the real one, hiding the root cause.

[Bugfix] Check tag before calling hook effects (#16215)


Prevent legacy React roots from erroneously clearing container content when a new root is rendered into the same container after the previous root is unmounted. In ReactDOM's legacy mode, calling `unmountComponentAtNode` (e.g., from within a focus event) followed immediately by a new `render` on the same container can leave the old root's discrete work pending. When that work commits, it still sees a `null` `current.child` and adds a `Snapshot` effect that clears the container—wiping out the newly mounted content. The fix should ensure that before adding a `Snapshot` to a HostRoot in `completeWork`, we verify that the container’s `_reactRootContainer._internalRoot` still matches the current fiber root; if it is null or references a different root, the `Snapshot` must not be set, so a stale root cannot destroy a newer root’s content. Apply this check in both `ReactFiberCompleteWork.new` and `ReactFiberCompleteWork.old`.

Prevent stale legacy root from clearing a container (DRAFT) (#18792)


**Title:** `eslint-plugin-react-hooks`: Forbid hooks inside class components

**Background**
The `rules-of-hooks` ESLint rule currently does not report hooks found inside class components. The original rationale was that hooks in classes would be runtime errors anyway, and that feature-flag/toggle patterns (e.g. `if (flag) { useFeatureFlag(); }` in a class `render`) caused too many false positives. The rule instead only enforces the “named like a hook / inside a function component or custom hook” invariant.

**Request**
Now that hooks are the dominant paradigm, flip the default: the linter **must** report *any* call to a hook-like function (`use[A-Z]…`) that appears inside a class component body – including `render`, class property initializers, and class methods.

**Expected behavior**
- The lint rule emits an error for every hook call found lexically inside a class.
- The error message must be explicit and disambiguate the problem:
  `React Hook "X" cannot be called in a class component. React Hooks must be called in a React function component or a custom React Hook function.`
- The previous exemption for class components (where the rule would silently accept hooks in classes) must be removed entirely.

**Acceptance criteria**
- A hook call inside any type of class member (method, arrow property, constructor, etc.) produces an error with the message above.
- The rule still correctly allows hooks in regular function components and custom hooks.
- No new false-positive concessions for classes (the old feature-flag pattern will now be flagged).

[eslint-plugin-react-hooks] Disallow hooks in class components (#18341)


**Title:** Press event hook silently ignores `stopPropagation`, `preventDefault`, and `preventContextMenu`

**Description**
When the Press responder is used via the event hook API (`React.unstable_useEvent(Press, {...})`), props that control side effects on native events (`stopPropagation`, `preventDefault`, `preventContextMenu`) are completely ignored – the native event still propagates, the default action still occurs, and the context menu is still shown. No warning is emitted, making it hard to understand why the props don’t work.

**Steps to reproduce**
1. Create a component that attaches a Press event hook with `stopPropagation: true`, `preventDefault: true`, or `preventContextMenu: true`.
2. Also have a Press element somewhere in the tree that does *not* rely on the hook (e.g., a normal `<Press>` wrapper).
3. Trigger pointer events on the target.

Example:
```jsx
function Comp() {
  React.unstable_useEvent(Press, { stopPropagation: true });
  return (
    <Press onPress={...}>
      <div ref={...} />
    </Press>
  );
}
```

**Expected behavior**
- `stopPropagation` / `preventDefault` / `preventContextMenu` should either work consistently or, if they cannot be supported in event hooks, React should **warn** that the prop is a no-op when passed to a hook. Execution of the corresponding native-side effect (`nativeEvent.stopPropagation()`, `nativeEvent.preventDefault()`) should not be attempted from within an event hook context.

**Actual behavior**
No warning is printed, and the props do nothing. The native event propagates and default behaviour occurs.

**Impact**
Developers may incorrectly assume the Press hook supports these props, leading to broken event handling (e.g., unexpected navigation on anchor clicks, context menus appearing, or events propagating to parent handlers). The lack of a warning makes debugging difficult.

**Additional context**
These props *do* work when used directly on the `<Press>` declarative component, so the discrepancy between the two APIs is confusing. The fix should ensure that when the event responder detects it is running inside a hook (`context.isRespondingToHook()`), it avoids the side-effects and warns in development.

[Flare] Ensure Press event hook does not execute side-effects (#15976)


We need to ensure the `useFocus`/`useFocusWithin` hooks correctly distinguish keyboard **navigation** from keyboard **text entry** when reporting focus visibility.

**Current behavior**
When an element receives focus via keyboard (e.g., Tab) the `onFocusVisibleChange` callback is invoked with `true` indicating the browser should show a focus ring. However, subsequent text entry within a focused `<input>` or `<textarea>` (or `contentEditable` element) currently also causes `onFocusVisibleChange(true)` to fire. This produces a visible focus ring appearing or re‑asserting itself while the user is simply typing, which is not the intent of `focus-visible`.

Similarly, the `onFocusWithinVisibleChange` callback inside `useFocusWithin` suffers from the same problem: typing inside a descendant input forces the containing element to signal visible focus.

**Desired behavior**

1. **`onFocusVisibleChange` / `onFocusWithinVisibleChange` must not fire in response to text‑input key presses.**
   When the user presses a key that would typically insert a character (letters, numbers, symbols, Space in a text field) inside an `<input>`, `<textarea>`, or `[contenteditable]` host, the focus‑visible state must not be set to `true`. The state should remain whatever it was before the key press.
   *This includes backspace, delete, and other editing keys when the target is a text‑entry element.*

2. **Non‑text keyboard interactions still trigger visible focus.**
   Pressing `Tab`, `Escape`, or arrow keys in a non‑text context (or even within a text field when they don’t insert characters) should still set focus‑visible to `true`, consistent with the browser’s native `:focus-visible` heuristic.

3. **Modifier‑only key presses must not signal visible focus.**
   Keydown events where `metaKey`, `altKey` (except on macOS), or `ctrlKey` are active should continue to be ignored for focus‑visible purposes, as they represent system shortcuts, not deliberate keyboard navigation.

4. **Pointer and touch interactions must clear visible focus.**
   Any mouse, touch, or pointer event received by the element (or within the boundary for `useFocusWithin`) should set focus‑visible to `false`, regardless of previous state.

5. **The callbacks must not be invoked when the value does not change.**
   If the focus‑visible state is already `false`, receiving a pointer event should not trigger `onFocusVisibleChange(false)` again.

6. **Timing**
   The initial focus state after mount must be set synchronously (e.g., using `useLayoutEffect` in the implementation) so that the first committed paint already reflects the correct focus‑visible state, preventing a frame where focus‑visible is inadvertently `true`.

**Affected API**
- `useFocus(focusTargetRef, { onFocusVisibleChange, … })`
- `useFocusWithin(ref, { onFocusWithinVisibleChange, … })`

Sync latest useFocus/useFocusWithin changes (#19397)


When a Server Component (or a `lazy` component wrapping a Server Component) throws an error during rendering on the client, the resulting error boundary’s component stack trace often omits the name of that Server Component. Instead the stack appears to jump from the last client component directly to the throwing child, making it hard to identify the faulty Server Component in the hierarchy.

**Desired behavior**
- The component stack for an error caught by an `ErrorBoundary` (or logged via `onCaughtError` / `onUncaughtError`) must include **all** components that were in the parent chain at the moment the error was thrown, including Server Components and other components that supply `_debugInfo` (e.g. lazy wrappers, async components).
- The order must mirror the normal React owner/component stack: parent components appear before their children, with the throwing component last (or immediately before the leaf that threw).
- The stack must be accurate **even if the error occurs during the reconciliation of a child** (e.g., inside a `createElement` or `lazy` initialization) and **even if the parent Server Component is not fully materialized** as a Fiber at that point.
- This should work for arbitrary nesting: client → Server Component A → Server Component B → throwing child → error boundary. Both A and B must appear, in that order, above the throwing child.

**Edge cases / constraints**
- If multiple `_debugInfo` entries exist (e.g., a `lazy` that wraps a Server Component), they should be merged in the correct parent-first sequence, consistent with how client component stacks are built.
- The debug info must be captured at the **point of the throw**, not at the point where the error Fiber is later processed, so that any subsequent changes to the active debug info (e.g., after unwinding) do not corrupt the stack.
- The fix must not regress the existing stack behavior for purely client-side errors.
- It must be compatible with Suspense boundaries: if a Server Component suspends and then later throws, the stack should reflect the hierarchy at the throw site, not a stale snapshot from initial rendering.
- In production builds the behavior is a no-op, but the tracking must not affect bundle size or performance.

[Fiber] Track debugInfo on module state instead of stack (#29807)


**Title:** Scheduler profiling event log grows unbounded, causing OOM crash when profiling is left running indefinitely

**Environment:** React Scheduler (internal profiling implementation enabled)

**Description:**
When `startLoggingProfilingEvents()` is called and the profiler runs for a long time without an explicit `stopLoggingProfilingEvents()`, the internal event log buffer (`Int32Array`) keeps expanding to accommodate new events. This buffer never stops growing, eventually consuming all available memory and causing the JavaScript VM to throw an out-of-memory error or crash.

**Expected behavior:**
- The event log buffer should have a maximum size limit (e.g., 2 MB of raw Int32 entries).
- When this limit is reached, the profiler should *automatically stop logging*.
- A clear console error/warning should be emitted, reminding the developer to call `stopLoggingProfilingEvents()` explicitly to prevent unbounded growth.
- After automatically stopping, the profiling state should be fully reset so that:
  - A subsequent call to `stopLoggingProfilingEvents()` returns `null` (indicating no data), rather than returning a corrupted or huge buffer.
  - A new profiling session can be started cleanly with another `startLoggingProfilingEvents()`.

**Impact:**
Without this limit, a long-running or forgotten profiling session can crash the application. The fix should make the profiling system safe for prolonged use and provide useful guidance to developers.

**Implementation notes (for internal reference):**
- The initial event log size is currently 131072 entries (1 element = 4 bytes).
- The buffer doubles each time it needs to grow; introduce a `MAX_EVENT_LOG_SIZE` of 524288 entries (2 MB) to cap growth.
- Modify the `logEvent` function to check the new size against the maximum and, if exceeded, call `stopLoggingProfilingEvents()` and `console.error` with a message like: `"Scheduler Profiling: Event log exceeded maximum size. Don't forget to call \`stopLoggingProfilingEvents()\`."`
- Ensure `stopLoggingProfilingEvents()` still returns a valid ArrayBuffer when called normally, but after auto‑stop it should return `null` (or a zero‑length buffer) and clear internal state.

[Scheduler] Prevent event log from growing unbounded (#16781)


The `Suspense` component currently captures a suspended subtree even when no `fallback` prop is provided. This renders nothing while suspended, which is rarely useful and prevents using `Suspense` solely for its `maxDuration` (timeout) control without a placeholder. Change the behavior so that `Suspense` only acts as a boundary when `fallback` is explicitly defined (not `undefined`). When `fallback` is missing, the suspended exception should propagate to the next parent `Suspense` component, just like an error boundary rethrow. If no ancestor provides a fallback, React must throw a descriptive error indicating that an update suspended but no placeholder UI was provided.

Suspense component does not capture if `fallback` is not defined (#13879)


We need to fix a bug in the `DEPRECATED_flareListeners` responder system (Flare) related to listener upgrading. When a responder initially registers for a base event type like `click` (passive), and later, during an event, calls `context.addRootEventTypes(['click_active'])` to upgrade to an active listener, the old passive listener is not properly removed. As a result, subsequent events fire the `onEvent` callback multiple times—once for the stale passive listener and once for the new active listener.

**Expected behavior:**
After an upgrade from a passive to an active event listener (or any change that replaces a trapped listener), each native event should invoke the responder’s `onEvent` exactly once. Duplicate invocations must not accumulate.

**Acceptance criteria:**
1. Attach a `DEPRECATED_flareListeners` responder to a DOM element for a target event type (e.g., `click`).
2. When the first event fires, call `context.addRootEventTypes` to switch to an active event type (e.g., `click_active`).
3. Fire the same native event a second time. The `onEvent` handler must be called exactly once (total invocation count should be 2 for two events, not 3 or more).
4. The fix must work regardless of whether the browser supports passive event listeners natively, and it must not regress the behavior for responders that only use passive or only active listeners from the start.

Flare: Fix listener upgrade bug (#18270)


**Title:** Add unstable SuspenseList type checks to `react-is` with channel gating

**Background**
The `react-is` package provides `typeOf` constants and predicate functions for built‑in React element types (e.g. `Suspense`, `Profiler`). `SuspenseList` is an experimental feature whose symbol (`REACT_SUSPENSE_LIST_TYPE`) already exists in shared internals, but there is no way for tooling (linters, devtools, test utilities) to identify a `SuspenseList` element through the public `react-is` API.

**Desired behavior**
- Add an `unstable_SuspenseList` export that holds the symbol for `SuspenseList` elements.
- Add an `unstable_isSuspenseList(object)` predicate that returns `true` exactly when `typeOf(object) === REACT_SUSPENSE_LIST_TYPE`.
- Because `SuspenseList` is experimental, these exports **must not** be present in the stable release of `react-is`. The stable entry point should continue to expose only the current set of stable type checks.
- The experimental entry point (`react-is/index.experimental.js`) should re‑export the new unstable identifiers alongside the existing stable ones.

**Constraints / edge cases**
- Follow the existing pattern for `Suspense` naming: the symbol is exported as `unstable_SuspenseList` and the predicate as `unstable_isSuspenseList`.
- The new predicate must behave identically to the other `is*` helpers: it should check the resolved type using `typeOf`, not perform a shallow property inspection.
- No breaking changes to the stable API; stable users must not see these identifiers at all.
- Ensure the build forking (stable vs experimental) is explicit so that a plain `import { … } from 'react-is'` resolves to the correct set of exports for the channel.


Add `PublicTextInstance` support to Fabric’s public instance accessor.

`getPublicInstanceFromInternalInstanceHandle` currently only handles host component (view) instances. Extend it to also handle `HostText` instances so that refs and `findNodeHandle` can reach raw text nodes, as required by [`react-native-community/discussions-and-proposals#607`](https://github.com/react-native-community/discussions-and-proposals/pull/607).

Requirements:

- When `getPublicInstanceFromInternalInstanceHandle` is called with a text node’s internal instance handle, return a `PublicTextInstance`.
- Creation must be lazy: the first access for a given text instance calls `ReactNativePrivateInterface.createPublicTextInstance(internalInstanceHandle)` and caches the result on the instance. All subsequent accesses for the same instance return the cached object.
- Text instances whose public instance is never requested must not incur extra memory overhead.
- Use the work tag (`HostText`) to distinguish text nodes from host components inside `getPublicInstanceFromInternalInstanceHandle`.
- Update the return type to `PublicInstance | PublicTextInstance` and ensure `PublicTextInstance` is exported through the required type declarations.

Implement public instances for text nodes in Fabric (#26516)


The `react-hooks/rules-of-hooks` lint rule must correctly recognize `do/while` statements as loop constructs that can cause hooks to be called more than once. Currently, a hook placed inside a `do/while` loop body may not produce any error, or may be incorrectly reported as a conditional-call violation instead of a loop violation.

### Acceptance criteria
1. **Loop detection**
   A call to a React hook anywhere inside the body of a `do/while` statement is treated the same as a hook inside a `for`, `while`, or `for...of` loop, regardless of how deeply nested the call is within the loop body.
2. **Correct error type**
   The rule must report the loop-specific “may be called more than once” error (i.e., the hook is called inside a loop) for `do/while`, and **must not** produce a conditional-call error for the same call site. The presence of `do/while` should take precedence over any conditional-path analysis.
3. **No false negatives**
   Every hook call inside a `do/while` loop triggers a lint error; there should be no silent acceptance.
4. **No false positives for conditional-call messages**
   Hooks inside `do/while` must not be misclassified as “called conditionally” in the output.
5. **Existing behavior for other loops is unchanged** – `for`, `while`, and `for...of` continue to work as before.

react-hooks/rules-of-hooks: Improve support for `do/while` loops (#31720)


In React Fiber's component stacks, errors inside a `<Suspense fallback={...}>` tree currently show the boundary's name as just "Suspense". Update the stack formatting so that components rendered in the fallback are attributed to a distinct built-in name: **"Suspense Fallback"** instead of "Suspense". This should apply when the stack is walked from the fallback fiber upward through the parent `Suspense` fiber. The change is a Fiber-side mirror of a similar improvement already applied to the other renderer.

[Fiber] Name content inside "Suspense fallback" (#33724)


We need to implement a new Scroll event responder component (`Scroll`) as part of the React Events system. This component will allow consumers to respond to scroll interactions with high-level events that include contextual information about the input device.

**Acceptance Criteria:**

1. **Component Usage**
   - The component is used as `<Scroll onScroll={handler} disabled={false}>{children}</Scroll>`.
   - It does not render any DOM elements itself; it wraps children and observes events.
   - A `disabled` prop can be set to `true` to suppress all custom event dispatching.

2. **`onScroll` Event Dispatching**
   - When a native `scroll` event fires on any target within the component’s subtree, a synthetic scroll event is dispatched to the `onScroll` callback.
   - The synthetic event has a `type` of `'scroll'`.
   - The event object includes:
     - `target`: the element or document that is the source of the original scroll event.
     - `pointerType`: a string indicating the last used input modality, derived from recent events (see below).
     - `direction`: reserved for future use; currently an empty string.
     - Coordinate properties (`clientX`, `clientY`, `pageX`, `pageY`, `screenX`, `screenY`, `x`, `y`) from the associated native event if available; otherwise `null`.

3. **Pointer Type Detection**
   - The `pointerType` in the dispatched event reflects the last primary user interaction:
     - If a `pointerdown` event (mouse, touch, pen) occurred most recently, the type is `'mouse'`, `'touch'`, or `'pen'` accordingly.
     - If a `keyup` event occurred most recently, the type is `'keyboard'`.
     - If no qualifying event has occurred, the type may be an empty string.
   - This ensures consumers can distinguish between scrolls initiated by touch, mouse wheel, pen, or keyboard.

4. **Disabled State Behavior**
   - When `disabled` is `true`, no `onScroll` callbacks are invoked, regardless of native scroll events.
   - Any internal state (e.g., pointer tracking) should be cleaned up appropriately when the component transitions to disabled mid-interaction (e.g., if a pointer was previously down, release tracking).

5. **Future Callback Placeholders**
   - The component should accept additional props that are not yet implemented: `onScrollDragStart`, `onScrollDragEnd`, `onScrollMomentumStart`, `onScrollMomentumEnd`.
   - These props should be recognized but should not trigger any dispatch in this initial implementation.

6. **Event Priority**
   - The dispatched `onScroll` event should have a user-blocking priority, ensuring it is handled promptly in the React scheduling system.

7. **Integration**
   - The module must be exposed via `react-events/scroll` and available as a standard event component through React’s experimental event API (`React.unstable_createEventComponent`).

The goal is to deliver a minimal viable Scroll event responder that accurately captures input modality during scrolls, laying the groundwork for future drag and momentum phases.

[Flare] Add basic Scroll event responder module (#15827)


**Bug Report: Out-of-bounds crash when EdenFS reports root inode change**

**Description**
When Watchman monitors a repository backed by EdenFS and the root directory inode changes (e.g., due to a “touch .”, creating a file directly under the root, or similar), Watchman crashes with an out-of-bounds memory access.

The root cause is in the EdenFS watcher’s handling of journal entries. For a root tree inode change, EdenFS supplies an empty path string. The current Watchman code strips the mount‑point prefix from the reported path by advancing past `mount_point + “/”`, but when the reported path is exactly the mount point (i.e., no trailing slash), the advance moves beyond the string’s length, causing undefined behavior / crash.

**Expected behavior**
- Watchman must not crash for any valid journal entry from EdenFS, including entries that represent a change to the repository root itself.
- The query response for such a root change should produce a valid file entry. The entry’s name field should correspond to the root directory’s basename (i.e., the name of the mount point), indicating that the repository root was part of the changed set.
- The handling should be correct regardless of whether the mount point path has a trailing slash or not – the relative name for the root should be treated as empty.

**Impact**
Any Watchman client using the EdenFS watcher will experience a crash whenever the repository root’s inode is modified, making the watcher unreliable for root‑level file operations. This prevents proper asset rebuilding and file monitoring for many common workflows.

fix the out of bound bug when handling response from EdenFS


```
## Title
Eden watcher does not respect `relative_root` and `ignore_dirs` in queries

## Observed behavior
When watchman is configured to use the Eden watcher backend, queries that include a `relative_root` constraint return:

- Files outside the `relative_root` subtree.
- Paths that still contain the `relative_root` prefix, instead of being relative to that prefix (as expected by clients and as the inotify watcher behaves).

Additionally, paths that are specified in the watch root’s ignore configuration (for example, `ignore_dirs` set in `.watchmanconfig`) are not filtered from query results or subscription events. This causes clients like Buck to receive file-change notifications for ignored directories (e.g. `buck-out`, `.buckd`), leading to assertion failures because the paths are not in the expected set.

## Expected behavior
The Eden watcher should produce the same filtering guarantees as the default (inotify) watcher:

1. **`relative_root` filtering:**
   For a query with a `relative_root` of `adir`, results must include only files whose full path is within that directory, and the returned file names must be relative to `relative_root` (i.e. `file` not `adir/file`).

2. **Ignore-dirs filtering:**
   Any path that matches an ignore rule (as defined by the watch’s `ignore_dirs` configuration, including the root-level `.watchmanconfig`) must be excluded from all query results and subscription events, regardless of whether the path was reported by the underlying Eden filesystem snapshot.

This filtering must apply consistently to every code path that generates query results when the Eden watcher is active. In particular, both the time‑based generator (`since` cursor) and the glob‑based code path must filter results.

## Additional notes
- The existing InMemoryView already has the necessary logic for these filters (e.g., `w_query_file_matches_relative_root`, `ignore.isIgnored`), but that logic is not presently wired into the Eden‑specific query generation.
- The fix should not require changes to the Thrift protocol or the Eden service; it is purely a watchman‑side filtering adjustment.
- Care should be taken that the `since` clock computation is not affected by the filter (i.e. we must still advance the cursor based on the raw Eden state, but only emit post‑filter results).
```

make eden watcher respect relative_root, ignore_dirs configuration


**Bug Report: w_string_suffix returns NULL for strings ending with a dot and has off-by-one in suffix-length limit**

`w_string_suffix` is supposed to extract the file extension after the last dot in the final path component (basename), returning a new non-NULL w_string for valid suffixes, or NULL if there is no dot. Current behavior violates that contract in several edge cases:

1. **Trailing dot**: A path like `"file."`, `"something."`, or `"."` should produce the *empty suffix* (a valid, zero-length w_string), because the dot is present but followed by nothing. Instead, the function returns NULL.

2. **Maximum suffix length**: The function uses an internal fixed-size buffer (`name_buf`) and returns NULL when the suffix would not fit. The length check appears to be off by one:
   - A suffix that is exactly one byte smaller than the buffer (i.e., `sizeof(name_buf)-1` characters) should be accepted, because we need room for the terminating null.
   - A suffix that exactly equals or exceeds the buffer size should be rejected with NULL.
   - The current arithmetic may incorrectly accept suffixes that are too long, or reject ones that should fit.

3. **Early exit during reverse scan**: While scanning backwards from the end of the path looking for a dot, the code should bail out early with NULL as soon as the unscanned remainder (the candidate suffix) reaches the buffer size, even before a dot is found. Otherwise it wastes work on a suffix that can never fit.

**Expected behaviour:**

- Paths whose final component ends with a dot (dot is the last character, or dot is immediately followed by end-of-string) → `w_string_suffix` returns a non-NULL, zero-length w_string.
- Paths whose final component contains no dot → returns NULL.
- Normal extensions (`"file.txt"` → `"txt"`, `".config"` → `"config"`, `"a.b.c"` → `"c"`) continue to work.
- Suffix length limits:
  - `sizeof(name_buf)-1` characters → accepted, returns the suffix.
  - `sizeof(name_buf)` characters or more → rejected, returns NULL, no buffer overflow.
- During the backward traversal, once `(remaining characters from current position to end) >= sizeof(name_buf)`, return NULL immediately.

**Acceptance criteria**:
- All the cases above produce the described results.
- Add unit tests covering: empty string, bare dot, trailing dot, no suffix, extension at beginning of basename, normal extension, exactly max-length extension, over-length extension (including cases where the over-long suffix would only be discovered late), and a case where the reverse scan can bail out early on a dotless, too-long component.

w_string_suffix return NULL if ends with '.'


Title: EdenFS subscriptions should not get stuck on SCM command failures

Problem: In the EdenFS watcher, if the SCM command used to compute the list of files changed between commits fails (for example, `hg` returns an error), the subscription silently stops delivering further updates and becomes permanently stuck.  This happens even after a single transient failure; the subscription never recovers.

Desired behavior:
- When such an SCM error occurs during journal processing (i.e., while trying to determine what files changed in a checkout), the watcher should:
  1. Log the error.
  2. Fall back to generating a **fresh instance** response for that subscription (as if a new subscription was established).
  3. **Not** let the exception propagate and halt the subscription's processing loop.
- The subscription must remain healthy: subsequent file modifications (e.g., a later `touch`) should be reported normally, showing that the subscription is not stuck.
- Only SCM-specific failures (errors originating from `hg` or the scm layer) should trigger this fallback.  Other kinds of unexpected runtime errors should still propagate, to avoid hiding unrelated bugs.
- The fresh instance fallback is acceptable even when `empty_on_fresh_instance` is `false` (which is the default), because a potentially expensive response is better than a broken subscription.

generate a fresh instance response on SCM command failure


**Title:** `dirname` expression with trailing slash causes EdenFS glob rejection

**Description**

When a Watchman query uses the `dirname` expression with a directory path that ends in a trailing slash (e.g., `["dirname", "some/dir/"]`), the query can fail if the EdenFS watcher is in use. The generated glob pattern for EdenFS’s upper bound ends up with a consecutive slash like `some/dir//**`, which EdenFS rejects as invalid.

Trailing slashes are a common user habit (shell completion, copy‑paste, etc.) and should be harmless. The observable requirement is:

- A query containing `["dirname", "dir/"]` must behave identically to one with `["dirname", "dir"]`—matching all files anywhere under that directory.
- The fix must ensure that the `dirname` argument is normalized before any glob or matching logic is applied: any trailing slashes are stripped. Multiple trailing slashes (e.g., `"dir//"`) should also be normalized down to the bare directory name.
- This normalization must not alter case‑sensitivity handling, depth‑related operators, or any other `dirname` semantics.
- The behaviour must be consistent across all watchers; the EdenFS rejection is simply the most visible symptom.

**Acceptance criteria**

1. A Watchman query using `["dirname", "adir/"]` on an EdenFS mount succeeds and returns the same file list as `["dirname", "adir"]`.
2. The same query on a non‑EdenFS mount (e.g., in‑otify or kqueue) also returns the same results and does not change the set of matched files.
3. The generated glob upper bound for EdenFS no longer contains consecutive slashes (e.g., `adir//**` is not produced).
4. Edge case: if the `dirname` value is only slashes (e.g., `"/"` or `"//"`), the expression should still work correctly and match the root; no double‑slash artefact should appear.
5. No existing `dirname` tests that rely on exact matching of the directory string (including trailing slash) should be broken; the change is a tolerance addition, not a contract shift.


We need a way to skip integration tests when a required watcher is not compiled into the Watchman server. Currently, the test that exercises broken eden mounts assumes eden support is always present, causing a failure in opensource builds where eden is not available.

Please:
- Automatically register a capability for every watcher at the point it is registered, using the naming convention `watcher-<name>`. This lets clients (including the test suite) check whether a specific watcher is available.
- Add a convenience method to the integration test base class that checks a server capability and skips the test if it is missing, wrapping the existing capability-check mechanism.
- Update any test that depends on a particular watcher (e.g., the broken‑eden‑mount test) to use that helper, so it is skipped instead of failing when the watcher is absent.

make it easier to skip based on capabilities


**Title**: pybser `loads()` segfaults on truncated / malformed BSER input

We use the `pybser` Python extension (bundled with Watchman) to decode BSER-encoded messages arriving from an untrusted network source. We are seeing the Python interpreter **crash with a segfault** when the `loads()` function is called with certain malformed BSER byte sequences. The parser must never crash—any malformed input must be rejected with a `ValueError` instead.

**Specific crash‑triggering inputs** (each causes a segfault):
- `b"\x02"`   – a `BSER_BYTESTRING` header byte with no length or data
- `b"\x03\x00"` – `BSER_INT8` tag with only one data byte (truncated integer value)
- `b"\x07"`     – `BSER_REAL` tag without the required 8‑byte double

**Expected behavior**
- Every `loads()` invocation on malformed input must raise a `ValueError` with an informative message (e.g., “input buffer too small for …”).
- The parser must **never** read past the end of the provided buffer.
- Length fields (array, object) must be sanity‑checked: if they exceed a reasonable maximum (like `UINT32_MAX`), the parser must raise an error before trying to allocate Python collections, avoiding integer overflows and runaway memory usage.

**Scope**
The fix should cover all entry points that read from the input buffer, including the integer, array, object, template, and the main recursive dispatcher. Every place that advances the read pointer or accesses header/content bytes must first verify that the read fits entirely within `[buf, end)`.

fix a bunch of buffer overflows in pybser


```
Title: Modernize `json_dumps` to return `std::string` for exception safety and performance

**Problem:**
The `json_dumps` function currently returns a `char*` that was allocated with `malloc`, and the caller is responsible for `free`ing that memory. This pattern is brittle:

- If an exception is thrown after `json_dumps` returns but before the caller calls `free`, the memory leaks.
- Internally, the implementation writes to a `strbuffer_t`, then copies the result into a newly allocated C string, adding an unnecessary copy.
- Multiple callers immediately wrap the raw C string into a `std::string`, resulting in additional copying and manual pointer checks (many of which only guard against a `NULL` return).

**Desired change:**
Change the public signature of `json_dumps` to return `std::string` instead of `char*`. The implementation should:

- Build the output directly into a `std::string` using `json_dump_callback` (no intermediate `strbuffer_t`).
- On failure (e.g., serialization error), throw an exception instead of returning `NULL`.
- Avoid any `malloc`/`free` for the result string.
- Be exception‑safe: if an internal failure occurs, no resources should leak.

**Caller impact & invariants:**
- All call sites that currently call `free()` on the returned `char*` must be adapted to rely on automatic `std::string` destruction (remove `free`).
- Code that checks for a `NULL` return must be updated to either trust the new exception behaviour or, in cases where a serialization failure is possible, catch the exception appropriately (previously failures were silently ignored via a null check; now they must be explicitly caught if the context cannot simply let the exception propagate).
- Places that extract a C pointer from the returned string (e.g., passing to a C API) should use the `.c_str()` member function, with attention to the lifetime of the temporary `std::string`.
- Performance: the change should eliminate at least one unnecessary copy of the entire serialized content.

**Scope:**
Update the `json_dumps` implementation and all in‑tree callers. Do not alter the semantics of the JSON being produced; only the ownership and error‑signalling model should change.
```

watchman: remove use of strbuffer type from json_dumps


Make the EdenFS watcher support the new streaming `streamChangesSince` API so that a since query can be interrupted early when many files have changed (avoiding expensive manifest fetches after a checkout).

Required behavior (controlled by a new Boolean config `eden_use_streaming_since`, default false):
- When this config is true, call `streamChangesSince` instead of the existing `getFilesChangedSince`.
- The stream may deliver a file multiple times (e.g., added then removed). Deduplicate so that the final record reflects the net result: a file that ends with zero net "add" / "remove" should be reported as modified, and only files that end with a net positive "add" count as new.
- Because the stream provides no ordering guarantees, if the same file appears with different `dtype` values, fall back to `UNKNOWN` and let watchman re-fetch the actual type from EdenFS.
- Honor the existing `eden_file_count_threshold_for_fresh_instance` threshold and `empty_on_fresh_instance` query flag: if the number of **distinct** changed files exceeds the threshold **and** the query has `empty_on_fresh_instance` set, stop the stream early and return a fresh instance (i.e., set `since.fresh_instance` and return an empty file list with the current journal position). This early interruption is the primary motivator for the streaming API.
- On any error from the stream, or if the threshold is exceeded and triggers a fresh instance, fall back to the existing `makeFreshInstance` logic (which sets `fresh_instance`, gets the current journal position, and returns `getAllFilesForFreshInstance`).
- The existing non-streaming code path (legacy `getFilesChangedSince`) must remain untouched and continue to work when `eden_use_streaming_since` is false.
- All existing error handling for `EdenError` and `SCMError` that currently returns a fresh instance must continue to do so, but via the shared `makeFreshInstance` helper to avoid duplication.

Note: The streaming API already returns a `ResultChangesSince` with the final journal position; use that to populate the result clock.

eden: use the streaming streamChangesSince when enabled


**Fix auto-layout connections to container elements (clusters)**

When a diagram contains an `ElementPresentation` that has children beyond `AttachedPresentation` (e.g., a Package or Component with nested shapes), the automatic layout plugin does not handle connections correctly. After layout, lines that were attached to such a container are disconnected or attached at incorrect positions.

The layout pipeline should:
- Render such presentation elements as Graphviz **clusters** (not plain nodes), so that edges can attach to the cluster boundary rather than to a single interior point.
- Enable **`compound=true`** on the whole graph and use **`lhead` / `ltail`** attributes on edges that connect to or from a cluster, so the edge properly terminates on the cluster’s bounding box.
- Ensure a small placeholder node exists inside each cluster so that edges have a valid anchor point for the DOT output.
- Correct the order of edge coordinate points when reading them back from the layout result; start and end points appear reversed compared to the original connection handles, which causes the line reconnection to swap the head and tail positions.

**Context & edge cases:**
- An `ElementPresentation` that contains *only* `AttachedPresentation` children should still be rendered as a plain node, not a cluster.
- `AttachedPresentation` items themselves should continue to be represented as tiny “point” nodes for clustering attachment.
- The parsing of edge position strings (e.g., `"1.0,2.0 3.0,4 5.0,6.0 7,8.0"`) should return points in the order they appear for the connection’s tail and head, matching the handle ordering in Gaphor’s line presentations.