**Title:** Make HelloRequest handling opt-in via `s2n_config_set_renegotiate_request_cb`, and normalise callback failures to `S2N_ERR_CANCELLED`

**Background**
`s2n_config_set_renegotiate_request_cb` lets an application install a callback that decides whether to accept or reject a TLS HelloRequest. Historically s2n‑tls silently ignored HelloRequests when no callback was installed. That changed: currently, even without a callback, receiving a HelloRequest triggers a fatal `no_renegotiation` alert, which breaks existing applications that depend on the old ignore behaviour.

Additionally, if a callback is installed but returns an error (for example due to a safety limit), the resulting error code is not normalised to a user‑visible cancellation, potentially leaking an internal error like `S2N_ERR_SAFETY`.

**Acceptance criteria**
1. **No callback → silently ignore.**
   When `s2n_config->renegotiate_request_cb` is `NULL`, a HelloRequest must be fully ignored: no alert sent, the connection remains open, and normal data exchange can continue.

2. **Callback installed → use its response.**
   If a callback is installed, invoke it as before. The response (`S2N_RENEGOTIATE_ACCEPT` / `S2N_RENEGOTIATE_REJECT`) must be honoured, including for SSLv3 connections (which should still follow the callback’s decision rather than unconditionally sending `handshake_failure`).

3. **Callback failure → `S2N_ERR_CANCELLED`.**
   Any non‑success return from the callback must be surfaced to the application as `S2N_ERR_CANCELLED` (consistent with other “application‑cancelled” paths), instead of leaking the raw internal error.

**Backward compatibility**
The “no callback” path must restore the historical behaviour where HelloRequests are ignored. This means existing applications that never registered a callback will no longer receive unexpected `no_renegotiation` alerts after this change.


We need to prevent s2n from being casually used as a TLS client, because the current client mode does not perform any certificate validation. A developer who tries to create a client connection without explicitly acknowledging this risk should get an immediate failure with a clear error.

**Acceptance criteria**

1. `s2n_connection_new(S2N_CLIENT, &err)` must *fail* (return NULL and set a human‑readable error string in `err`) unless the environment variable `S2N_ENABLE_INSECURE_CLIENT` is set to `"1"`.
2. When the variable is set, client connection creation succeeds as before.
3. Server‑mode connections (`S2N_SERVER`) are unaffected by the variable.
4. The error message should make it obvious that the client mode is deliberately disabled for safety reasons and mention the required environment variable.

Require S2N_ENABLE_INSECURE_CLIENT for client use


We are tasked with producing a brief, direct implementation request that could have motivated the given commit. The request should be framed as a terse implementation request, describing the problem and the desired behavioral change without revealing implementation details of the patch.

The commit removes the `s2n_hash_state` parameters from `s2n_ecdsa_keys_match`, making the function allocate and free its own temporary hash states internally. The underlying motivation is that `s2n_hash_new` allocates memory in FIPS mode, and since `s2n_ecdsa_keys_match` is only used during `s2n_config` setup (not on the request path), it simplifies the API and avoids burdening callers with hash state management. Additionally, the commit extracts local variables for deeply nested `EVP_MD_CTX` accesses in the EVP-based hash functions to improve readability.

The request must describe this in the voice of a realistic implementation request, focusing on the observable API awkwardness and the FIPS allocation concern, while also mentioning the readability improvement. It should not mention tests, commits, or specific code changes. It may naturally reference the function name and file areas.

Here is the generated request:

```
Simplify `s2n_ecdsa_keys_match` API: the function currently requires
callers to allocate and initialize two `s2n_hash_state` objects and pass
them in. This is unnecessary boilerplate; the hash states are only used
temporarily for the key matching check. Move the hash state management
inside the function: allocate and free them internally, and remove the
`state_in` and `state_out` parameters from the signature.

Note: in FIPS mode `s2n_hash_new` performs memory allocation, but since
`keys_match` is only called during `s2n_config` setup (not on the
request path), having it allocate internally is acceptable.

Also, in `crypto/s2n_hash.c`, the EVP-based hash operations repeatedly
access `state->digest.high_level.evp.ctx` and
`state->digest.high_level.evp_md5_secondary.ctx` across many lines.
Extract these into local variables to improve code readability without
changing behavior.
```

Remove hash state as ECDSA key match arg, clean up high level hashes


**Title:** Skip HMAC operations in `s2n_record_write` for cipher suites that do not use an explicit MAC

**Background**
`s2n_record_writev` currently performs `s2n_hmac_update` and `s2n_hmac_digest` for every record, even for cipher suites that do **not** rely on an explicit HMAC (e.g., AEAD, composite, and the null stream cipher used for plaintext handshake records). These unnecessary HMAC calls waste CPU time and risk leaving the HMAC state dirty in ways that could cause subtle bugs. Worse, the existing code advances the sequence number *before* the MAC is computed, which means the MAC is built over the wrong sequence number and will fail verification on the receiver.

**Desired behavior**

1. **Only perform HMAC work when required**
   When the cipher suite's `record_alg->hmac_alg` is `S2N_HMAC_NONE`, do **not** call `s2n_hmac_update`, `s2n_hmac_digest`, or any associated logic. In particular, skip the temporary “length placeholder” write + wipe cycle that existed solely to feed the header into the MAC.

2. **Correct MAC construction for suites that *do* use an HMAC**
   When `hmac_alg != S2N_HMAC_NONE`, compute the MAC over:
   - the current `sequence_number`
   - the record type (one byte)
   - the protocol version (two bytes), **except** for SSLv3 (`actual_protocol_version <= S2N_SSLv3`) where the version is omitted
   - the plaintext content length (two bytes, representing the length of the plaintext fragment, **not** the final TLSCiphertext length)
   - the plaintext fragment data
   Write the resulting digest into the output stuffer, reset the HMAC state, and report how many bytes were written for the MAC.

3. **Sequence number ordering**
   The sequence number used in the MAC **must** be the sequence number assigned to this record. Increment the sequence number only **after** the entire record (including the MAC and any encryption) has been written. Never advance the sequence number before the MAC is computed; doing so breaks MAC verification on the peer.

4. **No regression for CBC cipher suites**
   The change must not break any CBC-based cipher suites (including composite CBC). Add a new integration (self-talk) test that enumerates every available CBC and composite-CBC cipher suite, completes a handshake, exchanges application data in both directions, and confirms the negotiated cipher suite matches. This will give us confidence that the refactored record-write path produces interoperable records for all CBC variants.

**Constraints**
- The fix must be contained within the record-writing code path (`s2n_record_writev`).
- Do not change the public API or the way other record types (TLS 1.3 AEAD, etc.) are written.
- Maintain the existing SSLv3 MAC special case (omit the two-byte protocol version).

refactor: Avoid unnecessary s2n_hmac calls in s2n_record_write (#4539)


When `s2n_renegotiate_wipe` is used to reset a connection for a second handshake, the `renegotiation_info` extension in the next ClientHello should contain the verify_data from the previously completed handshake (per RFC 5746). Currently the wipe discards the handshake’s `client_finished` and `server_finished` data and resets `finished_len`, so the extension is empty on the re-handshake.

Make `s2n_renegotiate_wipe` preserve the finished data across the wipe: save `finished_len`, `client_finished`, and `server_finished` before the reset, and restore them afterward. In `s2n_client_renegotiation_send`, also guard against writing an empty verify_data when `finished_len` is zero — the extension should only be emitted when the data is available.

The behavior change means the handshake’s `renegotiation` flag is no longer explicitly cleared after a wipe (it already remains set), and the code can proceed with a secure renegotiation handshake without manually tampering with the flag.

Keep finished data on s2n_renegotiate_wipe (#3539)


**Title:** `s2n_recv` silently ignores non‑post‑handshake handshake messages after the handshake

**Description:**
After the TLS handshake completes, `s2n_recv` is used to read application data and process valid post‑handshake messages (KeyUpdate and NewSessionTicket). However, if the remote peer sends any other handshake message — for example a ClientHello, Certificate, Finished, EncryptedExtensions, or EndOfEarlyData — the current implementation **silently ignores** those messages. They are consumed without error, and `s2n_recv` returns success.

This is incorrect and a potential security concern: the post‑handshake phase must reject all handshake messages that are not explicitly allowed (i.e., KeyUpdate and NewSessionTicket). Silently dropping them may hide protocol violations, confuse early‑data state tracking, or allow an attacker to inject unexpected handshake messages that might be misinterpreted by the receiver.

**Expected behavior:**
When `s2n_recv` encounters a handshake record containing a message type that is **not** a valid post‑handshake message, it should return an error (`S2N_ERR_BAD_MESSAGE`). This applies to all handshake message types defined in the TLS specification (ClientHello, ServerHello, Certificate, etc.) with the sole exception of KeyUpdate and NewSessionTicket.

**Observed behavior:**
Any handshake message that is not explicitly handled (KeyUpdate or NewSessionTicket) falls into a default case that silently discards the message. `s2n_recv` does not signal an error, allowing the connection to continue as if nothing happened.

**Impact:**
- During early data processing, an EndOfEarlyData message (which must be processed via the handshake state machine, not `s2n_recv`) can be silently swallowed by `s2n_recv` instead of causing an error.
- An attacker could inject arbitrary handshake messages after the handshake without detection, potentially leading to state confusion or bypassing protocol enforcement.

**Suggested fix:**
In the post‑handshake receive path, explicitly list all known handshake message types that are not allowed after the handshake and return `S2N_ERR_BAD_MESSAGE` for each. The only allowed types should remain KeyUpdate and NewSessionTicket. The list should cover every handshake message type defined in `tls/s2n_handshake.h` (for example `TLS_CLIENT_HELLO`, `TLS_SERVER_HELLO`, `TLS_CERTIFICATE`, `TLS_FINISHED`, `TLS_END_OF_EARLY_DATA`, etc.). Unknown message types (those not in the list of known handshake messages) may still be silently ignored for forward compatibility, but all known non‑post‑handshake messages must be rejected.

Don't allow non-post handshake messages to be received post handshake (#2703)


**Title:** RSA‑PSS certificates are rejected during TLS 1.2 handshakes

**Report type:** Bug / feature gap

**Observed behavior**
When an s2n‑tls endpoint is configured with an RSA‑PSS certificate (a certificate whose signature algorithm is RSASSA‑PSS), the handshake succeeds only if the negotiated version is TLS 1.3.  If the same endpoint negotiates TLS 1.2 the handshake fails.  Other certificate types (RSA‑PKCS#1 v1.5, ECDSA) work normally across all supported versions.

**Expected behavior**
The TLS 1.2 specification defines signature algorithms for RSASSA‑PSS: `rsa_pss_pss_sha256`, `rsa_pss_pss_sha384`, and `rsa_pss_pss_sha512`.  s2n‑tls should allow those signature schemes to be negotiated when the protocol version is TLS 1.2, so that RSA‑PSS certificates can be used in TLS 1.2 connections.

**Non‑goals / invariants**
- TLS versions older than 1.2 (TLS 1.1, TLS 1.0, SSLv3) must **not** accept RSA‑PSS signature schemes.  They were never defined for those versions and should continue to be rejected.
- The change should apply consistently to all three RSA‑PSS PSS schemes (SHA‑256, SHA‑384, SHA‑512).
- Existing TLS 1.3 support for RSA‑PSS must remain intact.

**Impact**
RSA‑PSS certificates are increasingly issued by public CAs.  The current restriction forces deployments to either remain on TLS 1.3 (not always possible) or forgo RSA‑PSS certificates entirely, limiting certification‑authority choices and blocking alignment with modern cryptographic best practices.

feat: TLS1.2 support for RSA-PSS certificates (#4927)


Enforce `s2n_init` / `s2n_cleanup` calling rules

The API contract states that `s2n_init` must be called once before any other library use, and must not be called again without an intervening `s2n_cleanup`. This is not currently enforced, leading to undefined behavior when `s2n_init` or `s2n_cleanup` are called incorrectly (several cleanup steps are not idempotent).

Required behavioral changes:

- Make `s2n_init` fail with `S2N_ERR_INITIALIZED` when the library is already initialized.
- Make `s2n_cleanup` fail with `S2N_ERR_NOT_INITIALIZED` when it would perform an explicit, user-requested cleanup while the library is not initialized. (The explicit cleanup path is the one where `s2n_disable_atexit` was called and the caller is the main thread.)
- After a successful explicit cleanup, the library must become uninitialized so that a subsequent `s2n_init` can succeed again.
- The automatic atexit cleanup handler should remain unchanged; it must not enforce these rules and should still attempt cleanup silently.

Enforce init and cleanup calling rules (#3512)


**Request: Unify key-matching logic across all pkey types**

`s2n_pkey_match` currently dispatches to a per-type callback stored inside `struct s2n_pkey`. Each key type (RSA, ECDSA, RSA-PSS) implements its own static `keys_match` function. These implementations differ in details (e.g., RSA encrypt/decrypt roundtrip vs. ECDSA sign/verify, RSA-PSS combining parameter comparison and sign/verify) but all conceptually prove that the public key corresponds to the private key.

*We want a single, consistent match implementation that works for every key type and removes the per-type duplication.*

**Observable acceptance criteria**

1. **No per-type callbacks** – The `match` function pointer is removed from `struct s2n_pkey` (in `crypto/s2n_pkey.h`). The static match implementations in `crypto/s2n_rsa.c`, `crypto/s2n_ecdsa.c`, and `crypto/s2n_rsa_pss.c` are deleted (they should not be renamed, moved, or left behind as dead code).

2. **Type-agnostic match** – `s2n_pkey_match(pub, priv)` must directly determine whether `pub` and `priv` refer to a matching key pair, without delegating through any per-type callback.
   - If the keys are of different types, or are of the same type but do not correspond, the call must fail with `S2N_ERR_KEY_MISMATCH`.
   - Only a valid public/private pair of the same type returns success.

3. **Sign-then-verify approach for all types** – The unified logic must use a sign/verify roundtrip to confirm the keys match:
   - Hash a short fixed known input using SHA-256.
   - Sign the hash with the private key using a signature algorithm appropriate to the key type:
     - RSA → `S2N_SIGNATURE_RSA`
     - ECDSA → `S2N_SIGNATURE_ECDSA`
     - RSA-PSS → `S2N_SIGNATURE_RSA_PSS_PSS`
   - Verify the resulting signature with the public key using the same algorithm.
   - The implementation must use the generic `s2n_pkey_sign` / `s2n_pkey_verify` APIs, **not** type-specific internal sign/verify functions or direct OpenSSL structure access.

4. **No regressions in key-type handling** – The change must work for ECDSA, RSA, and RSA-PSS keys on all platforms where those types are supported. RSA-PSS support varies by platform; the matching logic must only be exercised when RSA-PSS keys are actually available.

5. **Safe resource management** – Any hash states, signature buffers, and temporary allocations must be correctly cleaned up (no leaks on either success or failure paths).

*The goal is to replace three divergent, type-specific match implementations with one readable implementation in `s2n_pkey_match` itself, preserving the same caller-visible contract.*

refactor: implement match the same for all pkeys (#5224)


```
Title: Use a dedicated error code for unsupported TLS protocol versions instead of S2N_ERR_BAD_MESSAGE

Currently, when the handshake is rejected because the peer’s offered TLS protocol version is not supported — for example, it is below the minimum version allowed by the configured cipher preferences, or (on the client side) the server version is greater than the client’s offered version — the library reports `S2N_ERR_BAD_MESSAGE`. This error is too generic; callers inspecting `s2n_errno` cannot tell the difference between a malformed message and a legitimate version mismatch.

Add a new, descriptive error code (e.g., `S2N_ERR_PROTOCOL_VERSION_UNSUPPORTED`) with an appropriate error string in the error table, and return it from all handshake validation code paths that currently raise `S2N_ERR_BAD_MESSAGE` after detecting an unsupported protocol version. The alert sent to the peer (`protocol_version`) should remain unchanged.

The change must cover version checks in both the server-side processing of ClientHello (including SSLv2-compatible ClientHello) and the client-side processing of ServerHello.
```

Set S2N_ERR_PROTOCOL_VERSION_NOT_SUPPORTED when client/server tls version is not supported instead of S2N_ERR_BAD_MESSAGE (#1233)


**Refactor: move state machine logic from `PeerMessageReceiverState` into `PeerMessageReceiver`**

The `P2PClientActor` currently manages two separate pieces of state: a `PeerMessageReceiver` and a `PeerMessageReceiverState`. The state is passed around as an explicit parameter to methods on both the receiver and the state object. This splits responsibility and leads to awkward call sites where the actor must coordinate the two.

We want `PeerMessageReceiver` to own its state entirely. All state-transition methods currently defined on `PeerMessageReceiverState` — `connect`, `disconnect`, `initializeDisconnect`, `onResponseTimeout`, `handleExpectResponse`, `stopReconnect` — should be moved to `PeerMessageReceiver`. The receiver should keep track of its state internally instead of requiring the caller to supply it.

The `P2PClientActor` should no longer hold a separate `PeerMessageReceiverState`; it should only keep a mutable reference to a single `PeerMessageReceiver` and delegate state transitions to it. The `handleNetworkMessageReceived` method on the receiver should use its own state rather than accepting a state parameter.

Update all construction and usage sites accordingly:
- `P2PClientActor` constructor and companion `props`/`apply` methods should accept only a `PeerMessageReceiver`, not a separate state.
- `PeerData` and the test utility helpers (`NodeTestUtil`, `NodeUnitTest`) must be adjusted to pass a fully-initialized receiver with state.

The old test class `PeerMessageReceiverTest` that tested state transitions directly on the state objects is no longer appropriate and should be removed.

**Important invariants**: the state machine logic must remain identical. Transitions must still properly handle completion of connection/disconnection promises, scheduling of initialization timeouts, sending of version messages, response timeout handling, and reconnection stops. The behavioral semantics of each state transition must not change.

Move `PeerMessageReceiverState` into `PeerMessageReceiver` (#5110)


**Bug Report: Tapscript validation weight (sigops budget) not enforced**

**Observed behavior:**
Taproot script-path spends that include many signature operations (e.g., repeated `OP_CHECKSIGADD`) are succeeding even when they exceed the BIP 342 defined sigops budget (validation weight). Transactions that should be rejected with a sigops count exceeded error are being accepted.

**Expected behavior:**
For tapscript execution, the sigops budget (validation weight) must be enforced as specified in BIP 342:

- The initial budget is `50 + total witness size` (in bytes).
- Each `OP_CHECKSIG` or `OP_CHECKSIGADD` that carries a non-empty signature consumes 50 from this budget.
- If the budget would become negative, execution must fail immediately with a sigops limit error (`ScriptErrorSigCount`).
- Other signature versions (`SigVersionBase`, `SigVersionWitnessV0`, key-path spends) are not affected and should not have this budget tracking.

**Impact:**
Non-standard or deliberately bloated tapscript transactions pass validation when they should be rejected, violating network consensus rules and potentially allowing resource-exhaustion vectors that other implementations would block.

tapscript/sigopsratio_3 failing correctly (#4461)


**Title:** Remove redundant `syncing` flag from `DataMessageHandler` and fix state initialization / IBD detection

**Area:** node networking (DataMessageHandler, NeutrinoNode, PeerManager)

**Problem**
`DataMessageHandler` currently has both a `syncing: Boolean` parameter and a `syncPeer: Option[Peer]`, but `syncing` merely duplicates the semantics of `syncPeer.isDefined`. This duplication has led to cases where `syncing` and `syncPeer` drift apart, causing incorrect behavior during sync transitions, peer disconnection, re-sync, and IBD detection. Additionally, the handler’s initial state (filter header height, filter count, and reliance on `initialSyncDone` for IBD checks) is hardcoded rather than derived from the actual chain store, so the handler can start with stale heights or misunderstand whether IBD is in progress.

Concrete symptoms:
- When a sync peer disconnects, the node sometimes fails to pick a new peer correctly because the `syncing` flag is out of sync with the `syncPeer` reference.
- The IBD detection logic uses `initialSyncDone` (a manually crafted promise) rather than the authoritative `chainApi.isIBD()`, so after a restart or in certain test setups it makes wrong decisions about whether to process block headers as real-time blocks.
- The handler is sometimes built with a bare `genesisChainApi` that doesn’t reflect the node’s actual filter state, so callbacks (e.g. `OnCompactFilterReceived`) never fire because the handler thinks it has no filters to expect.
- After sync completes, the sync peer is not consistently cleared, leading to stale references that confuse later reconnection logic.

**Expected invariants & desired behavior**
1. **Remove the `syncing` field.** `DataMessageHandler` should rely solely on `syncPeer` (or a derived `syncing` getter that evaluates `syncPeer.isDefined`) to determine sync state. Every update that currently mutates `syncing` must instead adjust `syncPeer` accordingly (set to `Some(peer)` when sync begins, `None` when sync completes).

2. **Initialize the handler from the actual chain store.**
   - `NeutrinoNode` should load the current filter header count and filter count from the database when constructing its `DataMessageHandler`. If counts are zero, the height options should be `None`; otherwise they should reflect the true persisted heights.
   - The handler should use the node’s real `ChainApi` (obtained from `chainApiFromDb`) instead of a synthetic `genesisChainApi`.

3. **IBD detection must use the chain API.**
   - The handler’s path selection for incoming block headers should consult `chainApi.isIBD()` rather than checking whether `initialSyncDone` has completed. During IBD the handler should skip header processing (just fire callbacks); when IBD is finished it should process the header through the normal payload path.
   - The `initialSyncDone` promise should be removed entirely.

4. **Sync peer lifecycle.**
   - When a peer disconnects mid-sync, the `PeerManager` should trigger a sync from a new peer. The handler’s `syncPeer` must be replaced appropriately; after the new sync finishes (or if sync stops), `syncPeer` must revert to `None`.
   - Log messages for peer disconnect and sync restart should be upgraded to `INFO` to make this state machine observable.

5. **Resetting the handler** (via `reset`) must clear `syncPeer` (and thus `syncing`) without a separate `syncing` flag.

6. **Self-consistency in `DataMessageHandler` state transitions.**
   - All `.copy` calls that previously updated both `syncing` and `syncPeer` must now only update `syncPeer`.
   - The private `syncing` getter (derived from `syncPeer.isDefined`) should be used everywhere that formerly read the parameter.

**Acceptance criteria (behavioral)**
- A node that loses its sync peer while syncing should successfully connect to another peer, continue syncing, and eventually finish with `syncPeer = None`.
- A node that restarts after receiving some filters should not re-request them from the beginning; it should pick up at the next height.
- Compact-filter callbacks fire during sync when the handler is backed by the real chain API.
- Blocks arriving after IBD completion are processed as regular blocks (not ignored).
- No stale sync-peer references remain across sync cycles.


**Title:** Reserved UTXO spent in a block does not set `spendingTxId`

**Description:**
When a UTXO is in the `Reserved` state (e.g., the wallet reserved it because a spending transaction was created/broadcast while the wallet was offline or before confirmation) and later a block containing that spending transaction is processed, the UTXO transitions to `PendingConfirmationsSpent` but the `spendingTxId` field is not populated. This leaves the UTXO in a spent state without knowing which transaction spent it, breaking downstream tracking.

Additionally, reserved UTXOs that are still receiving confirmations (e.g., `PendingConfirmationsReceived` UTXOs that were marked as reserved) should remain reserved when a block is processed, as long as they are not actually being spent in that block. Currently they may be incorrectly moved out of the `Reserved` state or have their state changed prematurely.

**Expected behavior:**
1. When processing a block, a reserved UTXO that is an input to a transaction in that block must transition to `PendingConfirmationsSpent` with its `spendingTxId` set to the spending transaction’s txid.
2. Reserved UTXOs that are **not** being spent in the processed block must stay in the `Reserved` state, preserving any previously assigned `spendingTxId`.

**Edge cases to handle:**
- A reserved UTXO that is already `PendingConfirmationsReceived` and later reserved should survive block processing without state change unless it is spent.
- Processing a block that does not contain a transaction spending a reserved UTXO must not alter that UTXO’s state or clear its reservation.
- The spending transition must go through the normal path that assigns `spendingTxId` (the one used for non-reserved spent UTXOs), rather than a special-case state change that bypasses that assignment.

Fix bug where we didn't set spendingTxId when transitioning from `Reserved` -> `PendingConfirmationsSpent` (#3909)


```
Title: Make AesEncryptedData a NetworkElement / Factory

Background:
In the `crypto` module, many types implement the `NetworkElement` trait (providing a canonical binary representation via `bytes`) and their companion objects implement `Factory`, which supplies a `fromBytes` method for deserialization. `AesEncryptedData` currently only supports base64 encoding/decoding via `toBase64` and `fromBase64`, and does not expose a raw byte-level serialization or conform to this pattern.

Ask:
- Make `AesEncryptedData` extend `NetworkElement` and its companion object extend `Factory[AesEncryptedData]`.
- The binary format is unchanged: IV bytes concatenated with ciphertext bytes (the same format already used by the base64 methods). Expose this via a `bytes` member.
- Implement `fromBytes(bytes: ByteVector): AesEncryptedData` that splits the input at the IV length, interprets the first part as an IV, and constructs the value. It should require the input length to be strictly greater than the IV length.
- Refactor `fromBase64` to reuse `fromBytes` so that the binary splitting logic is not duplicated.
- Fix the comment typo "AesEncryptedDatt" → "AesEncryptedData" in that method.
- Ensure a round-trip identity: `AesEncryptedData.fromBytes(enc.bytes) == enc` for any `AesEncryptedData`.
```

Make AesEncryptedData a network element / factory (#3952)


```
Title: Neutrino filter sync fails when receiving duplicate compact filter messages

During the neutrino filter synchronization phase, the node can stall permanently if a peer sends a compact filter that has already been processed. This often occurs when reconnecting to a peer that retransmits filters we already have, or occasionally when a peer sends the same filter more than once within a single batch.

Current behavior: a `DuplicateFilters` exception is thrown, causing the sync operation to fail and the node to stop making progress. The wallet remains unsynchronized and cannot complete initial sync.

Expected behavior: duplicate filters (whether already stored in the database or repeated within the incoming batch) should be silently skipped. The sync should continue as if those messages were never received.

Impact: users cannot complete initial sync if they ever encounter duplicate filter messages, leaving the wallet stuck.

The fix should ensure that:
- Filters that have already been persisted to the compact filter store are not re-inserted.
- Filters appearing more than once within a single incoming batch are handled safely and do not cause an error.
- No exception is raised for duplicate data; instead the sync loop continues normally.
```

2023 02 27 Fix bug where duplicate filters caused node not to sync (#5008)


When a DLC closing transaction is detected and the counterparty (remote) has claimed the funds, the wallet attempts to recover the oracle outcome and aggregate signature from the on-chain CET. The recovery process correctly infers which outcome was used, but the DLC state is updated to `RemoteClaimed` *before* the outcome and signature are persisted. If the recovery step fails or is interrupted, the DLC record can become permanently stuck in `RemoteClaimed` without the correct outcome, signature, or updated nonce/announcement usage. This leaves the database inconsistent and leads to an incorrect status being displayed.

Additionally, the recovery logic does not verify that all required data is still present. In particular, if the accept message, the refund signature, or the CET signatures have been pruned from the database, the wallet may silently produce an incomplete `RemoteClaimed` state rather than reporting a clear error. The computed oracle outcome seen by the `RemoteClaimed` side should always match the outcome recorded on the claiming side’s `Claimed` status; currently there is no explicit check for this equivalence.

Expected behaviour:
- The transition to `RemoteClaimed`, the recovered oracle outcome, the aggregate signature, and the marking of used nonces/announcements must all be applied atomically. If any step fails, the state must not advance.
- Before computing the outcome, the wallet must assert that the accept message, refund signature, and CET signatures are available. Missing data should cause the operation to fail with a descriptive error rather than leaving the DLC in an invalid state.
- The wallet should be robust against re-processing an already-closed DLC so that the outcome is not recalculated unnecessarily.

2022 02 06 remoteclaimed refactor (#4054)


Move `DataMessageHandler` ownership from `Node`/`NeutrinoNode` into `PeerManager`. The handler contains peer-related sync state and is already used by `PeerManager`; the `Node` should not own or directly expose its handler.

**Acceptance criteria**

1. **`Node` trait no longer exposes handler**
   - Remove `getDataMessageHandler` and `updateDataMessageHandler` from the `Node` trait. Callers must obtain the handler through `peerManager.getDataMessageHandler`.

2. **`PeerManager` owns the handler**
   - `PeerManager` should construct and hold a `DataMessageHandler` instance.
   - Provide a public `getDataMessageHandler` accessor.
   - Provide a public `updateDataMessageHandler(newHandler)` that returns the updated `PeerManager` (not `Node`).
   - Initial construction requires a `walletCreationTimeOpt`. The handler’s initial chain API should come from the database via `ChainHandler.fromDatabase()`.
   - The `PeerManager` constructor must accept `walletCreationTimeOpt: Option[Instant]`.

3. **Handler access consistent throughout**
   - All existing usages that previously called `node.getDataMessageHandler` or `node.updateDataMessageHandler` must be updated to go through `node.peerManager.getDataMessageHandler` / `node.peerManager.updateDataMessageHandler`. This includes:
     - `NeutrinoNode` itself (e.g., when setting the `syncPeer` during `sync()`, and in `syncCompactFilters`).
     - `PeerData` constructing a `PeerMessageReceiver`.
     - `PeerManager`’s own data-message stream and timeout recovery logic.
     - Test helpers and test cases.

4. **Resync-on-peer-loss delegated to `Node`**
   - Introduce a `syncFromNewPeer(): Future[Unit]` method on `Node`. Its implementation should reset the handler (via `peerManager.updateDataMessageHandler(getDataMessageHandler.reset)`) and then call `sync()`.
   - `PeerManager` must call `node.syncFromNewPeer()` instead of performing an in-place handler reset + `sync()` when:
     - A client stops and the disconnected peer was the active sync peer (and other peers are available).
     - A non-header query times out and the timed-out peer is the active sync peer.
     - A header request times out while in `HeaderSync` state.

5. **No change to external sync behavior**
   - After the refactoring, syncing, re-syncing on peer disconnect/timeout, and validation should behave identically to before.
   - The `DataMessageHandler` instance must remain a single mutable instance that flows through the same `reset`, `handleDataPayload`, and `copy` paths as before.

2023 04 22 peermanager dmh refactor (#5057)


**Backlog ticket: Simplify `PeerMessageReceiver` by removing the `PeerMessageReceiverState` state machine**

The `PeerMessageReceiver` currently carries a `PeerMessageReceiverState` that explicitly tracks connection lifecycle states (Preconnection → Initializing → Normal, Waiting, InitializedDisconnect, etc.).  Managing this state injects significant complexity, has led to edge-case bugs where valid messages are dropped because the receiver is in an unexpected state, and makes the connection handshake rigid.  We want to simplify the receiver so that it no longer maintains this state machine; instead it should process all incoming messages uniformly, regardless of the connection phase.

**What needs to change (behavior-focused)**

1. **No internal state machine** – Remove the `PeerMessageReceiverState` type entirely.  The receiver must no longer branch on `state` when handling incoming messages.  `handleNetworkMessageReceived` should simply dispatch the payload to the appropriate handler (`ControlPayload` → control handler, `DataPayload` → data handler) and return the receiver unchanged (no state transitions).

2. **Connection initialisation timeout** – When the underlying TCP connection is established, the receiver must still schedule an initialisation timeout so that if the peer never completes the version / verack handshake, we don’t wait forever.  The `connect` method should no longer set an `Initializing` state; instead it should directly schedule a `NodeStreamMessage.InitializationTimeout` via the queue and return a `Cancellable`.  The caller (primarily `PeerMessageSender`) is then responsible for cancelling this timeout once the handshake succeeds or the connection is torn down.

3. **Handling handshake messages** – The `ControlMessageHandler.handleControlPayload` method should no longer receive or return a `PeerMessageReceiverState`.  It should simply act on the message (e.g., call `peerManager.onVersionMessage` / `sendVerackMessage`, or offer an `Initialized` stream message) and return `Future[Unit]`.  No more runtime exceptions for “unexpected” states during version/verack processing – the handlers should be unconditionally invoked.

4. **Removal of the “Waiting for response” tracking** – The receiver should stop tracking whether it is expecting a response to a particular `ExpectsResponse` message.  Remove the `handleExpectResponse` method and the `Waiting` state entirely.  The scheduling and handling of response timeouts is already managed by `PeerManager` (via `SendResponseTimeout` / `QueryTimeout` stream messages), so the receiver does not need to maintain its own `Waiting` state or schedule timeouts.  This also removes the `onResponseTimeout` method.

5. **Disconnection without state transitions** – The `disconnect` method should no longer inspect the current state to decide what to do.  It should simply enqueue a `NodeStreamMessage.DisconnectedPeer` message and return the same receiver.  The caller should be able to disconnect in any phase without hitting `RuntimeException`.

6. **PeerMessageSender adjustments** – `PeerMessageSender` currently peeks at the receiver’s state before processing incoming messages.  This must be removed; message processing must proceed regardless of phase.  Additionally, `PeerMessageSender` should call the updated `connect` method to obtain the initialisation `Cancellable` and cancel it when the handshake completes.

**Safety / non-obvious constraints**

- The initialisation timeout must still fire if the handshake hangs; the `InitializationTimeout` message must be offered to the queue, and the `PeerManager` logic that reacts to it (shutting down the connection) must remain unchanged.
- When the handshake completes successfully, the `InitializationTimeout` must be cancelled.  If the connection is torn down before initialisation, the cancellable must be cancelled as well to avoid a stale timeout message.
- Any place that constructs a `PeerMessageReceiver` (including test utilities) must no longer pass a `state` argument.  Thorough search for all construction sites (`PeerData`, `PeerMessageSender`, testkit) is expected.
- The `ControlMessageHandler` must no longer import or reference `PeerMessageReceiverState`.

The intended outcome is a simpler, more robust `PeerMessageReceiver` with no explicit state tracking, where all messages are always processed, and the initialisation timeout is handled via a simple cancellable that the caller manages.


In `SendFundsHandlingHandling`, the two overloads of `sendFromOutPoints`—one that sweeps the entire balance and one that takes an explicit amount—duplicate the UTXO resolution and transaction building logic. The sweep variant also does not reject an empty outpoints list.

Refactor the sweep variant so that it reuses the amount-based method after computing the sendable amount as total UTXO value minus the estimated fee. Ensure that calling the sweep overload with an empty outpoints vector fails with `IllegalArgumentException` before any database work. Consolidate the logic for fetching previous transaction data for UTXOs so that both send paths and the fund-transaction pipeline share the same implementation, eliminating duplicated code and the risk of behavioral drift.

wallet: Remove duplicate implementations of `SendFundsHandlingHandling.sendFromOutpoints()` (#5792)


```
Title: TapscriptControlBlock construction ignores key parity, produces invalid control blocks

The `TapscriptControlBlock.apply(leafVersion, internalKey, leafHashes)` helper
constructs the control block’s first byte as `(leafVersion.toByte | 0x1).toByte`.
This always forces the parity bit to 1 (odd parity), which is only correct when
the internal key has an odd Y coordinate. For keys with even parity the resulting
control block is invalid, and taproot script-path spends built via this API will
fail validation.

BIP 341 defines the first byte of a Tapscript control block as:
  (leaf_version & 0xFE) | parity_bit
where parity_bit is 0 for even Y and 1 for odd Y.

We need to:

1. Accept `KeyParity` information when constructing a `TapscriptControlBlock`
   from leaf version, internal key, and merkle-path hashes. The first byte must
   be composed from the leaf version and the provided parity, not hard-coded.

2. Remove (or rework) the existing `fromLeaves` method, which has no way to
   express parity and therefore cannot be fixed to produce correct blocks.

3. Provide a way to build a control block for the common case of a single-leaf
   tree (where the merkle path is empty). That helper should also accept the
   parity. The current `fromLeaves` signature could be replaced with a
   single-leaf constructor that takes `leafVersion`, `internalKey`, and
   `parity` but no extra leaf hashes.

The parsing side (`TapscriptControlBlock(bytes)`) already exposes `parity` via
the low bit of the first byte, so the round-trip symmetry should be restored
between parsing and construction.
```

core: Fix `TapscriptControlBlock` bugs (#5955)


Fix the `closeChannel` methods in the LND RPC client (the ones that return a future) so they reliably return the closing transaction’s TXID rather than the funding outpoint, and correctly process both cooperative and force‑close paths.

Currently the stream only accepts `ClosePending` updates and returns a `TransactionOutPoint` built from the funding details. That means force closures and some failed ‑close scenarios are either ignored or cause the future to never complete.

Required behavior:
- Accept both `ClosePending` (cooperative close) and `ChanClose` (force‑close / non‑cooperative close) updates from the close‑channel stream.
- Extract the closing transaction’s TXID (the hash of the transaction that spends the channel) and return it in big‑endian form.
- If a `ChanClose` update indicates the close failed (`success == false`), fail the returned future with an appropriate exception.
- Update the overloads that delegate to the request‑based `closeChannel` so all callers observe the new return type.

Fixes for force closes or failure to close lnd channel (#4692)


**Bug report: UTXO state fails to advance to ConfirmedReceived when a single block contains multiple wallet transactions**

**Observed behavior**
When a block contains two or more transactions that each send coins to the wallet, some of the resulting UTXOs never reach `ConfirmedReceived` — even after more than the required number of confirmations (typically 6). They remain stuck in `PendingConfirmationsReceived` (or even `BroadcastReceived`), while other UTXOs from the same block may transition correctly.

**Steps to reproduce**
1. Create several new addresses in the wallet.
2. From an external source, send separate transactions to these addresses in such a way that they all end up in the same block.
3. Call the wallet's `processBlock` (or equivalent block-processing entrypoint) with that block.
4. Mine additional blocks until the receipt transactions have at least 6 confirmations, calling `updateUtxoPendingStates` appropriately.
5. Query the UTXO states.

**Expected behavior**
Every UTXO originating from a wallet-relevant transaction in a block should transition through the standard lifecycle: `BroadcastReceived` → `PendingConfirmationsReceived` → `ConfirmedReceived` once the required number of confirmations is met. The presence of multiple wallet transactions in a block should not interfere with any single UTXO's state progression.

**Impact**
- Funds can be shown as not yet confirmed even though they are deeply buried, leading to incorrect available balances.
- Spending may be blocked because the wallet treats the UTXOs as unconfirmed or pending.
- The problem only appears when a block contains more than one wallet-relevant transaction; single-transaction-per-block scenarios work fine, making the bug easy to miss in simple tests.

**Additional context**
The issue seems related to how wallet-relevant outputs are collected from a block and then forwarded to the individual transaction-processing logic. When a block has multiple relevant transactions, it looks like outputs from the entire block are being passed to each transaction instead of only the outputs belonging to that transaction, causing state tracking to break.

Fix unconfirmed -> confirmed state change (#4816)


**Request: Randomize the wallet default account type in tests and harden all account-type code paths**

**Context**
Our test infrastructure currently hardcodes the wallet's `defaultAccountType` to segwit. We are therefore missing bugs that only surface when wallets use legacy, nested-segwit, or taproot accounts. We want to exercise all four account types in tests, while keeping DLC tests locked to segwit (since DLC output types currently only support segwit v0).

**Acceptance criteria**

1. **Randomized default account type for regular wallet tests**
   The test configuration factory must randomly assign one of the four supported account types (`legacy`, `nested-segwit`, `segwit`, `taproot`) as the wallet's `defaultAccountType` for each test-suite run. This randomization must apply to all non-DLC wallet tests. For DLC tests, the default account type must remain **segwit only**.

2. **DLC test isolation**
   The existing dual-wallet test trait that is used by DLC tests must be replaced by a new trait that explicitly forces a **segwit** wallet configuration for the second wallet, overriding the randomization. The DLC wallet code itself should not hardcode segwit when it retrieves the default account; it should use the wallet's actual default account (which, for DLC, the test harness guarantees will be segwit).

3. **Address handling for all purposes**
   The address-derivation logic in `AddressHandling` must not throw an exception for any of the four purposes. Currently `Taproot` is missing from at least one of the HDPurpose match branches. Ensure that key path generation and address creation handle each purpose correctly.

4. **PSBT signing for nested-segwit**
   In the `ProcessBlockTest` transaction-signing path, when the wallet’s account is nested-segwit, the PSBT must include the redeem/witness script for the input. The test's PSBT construction must detect nested-segwit (via the account's extended key version) and add the `P2WPKH` witness script accordingly.

5. **No regressions**
   All existing tests must continue to pass with the randomization in place. The changes should only broaden coverage, not alter the semantics of any tested behavior.

**Non-obvious constraints**
- Nested-segwit inputs require extra data in the PSBT: when the output being spent is P2SH-P2WPKH, the PSBT input must include the inner witness script (`P2WPKHWitnessSPKV0`). The existing test code assumes segwit-only; it must become purpose-aware.
- The DLC wallet’s offers and accepts currently call `getDefaultAccountForType(AddressType.SegWit)`. Those calls must be changed to `getDefaultAccount()`, and the test harness must ensure the wallet’s default is segwit whenever DLC operations are exercised.
- The randomization should be applied at the test-configuration level (e.g., in `BitcoinSTestAppConfig`) so that every test suite that builds a wallet configuration automatically gets a random default account type. DLC test suites can override it to segwit.

**Desired outcome**
A test suite where the wallet’s default account type is randomly chosen across the four supported BIP purposes, and all production code paths (address derivation, PSBT building, DLC offer/accept) work correctly with whatever type is active. DLC tests remain fixed to segwit.

testkit: Randomize defaultAccountType (purpose) in tests (#5775)


The coin selection logic (accumulate, random, least-waste, etc.) is currently coupled to `SpendingInfoDb`, a wallet-internal database row type. That makes the coin selector unusable outside the wallet and forces any caller to depend on the wallet's data layer. Additionally, the `approximateUtxoSize` helper falls back to a hardcoded size for P2PKH when no redeem or witness script is provided, which is wrong for native witness (P2WPKH) and taproot (P2TR) outputs.

Decouple the coin selection from Bitcoin-S wallet internals:

* The coin selection API should accept a minimal, dedicated UTXO representation that contains only the information needed for selection: the prevout (amount + scriptPubKey), the outpoint, and optional redeem/witness scripts. It must not depend on `SpendingInfoDb` or any wallet database type.
* The wallet's transaction funding path should convert its `SpendingInfoDb` utxos into this representation before passing them to the coin selector, and then map the selected items back to the original `SpendingInfoDb` instances for downstream use (e.g., marking as reserved).
* The `approximateUtxoSize` method must inspect the scriptPubKey type of the prevout and return appropriate script sizes: ~107 bytes for non-witness (P2PKH/P2SH), ~107 for P2WPKH, ~64 for single-sig Taproot (P2TR), and 0 for unknown witness types rather than always falling back to 107.

The coin selection behavior (selection algorithms, fee calculations, etc.) should remain unchanged; this is purely a refactoring of the data that flows through the selection API. All existing tests for coin selection and wallet sending should continue to pass after the change.

Refactor coin selection to be not be bitcoin-s specific (#4496)


In the Bitcoin‑S server, wallet node callbacks are wired through a shared Akka `KillSwitch`. When the server shuts down the kill switch, callbacks that are still in flight can be dropped immediately. This can cause the wallet to miss transaction notifications and fail to update its balance.
Please replace the kill-switch mechanism with a stream‑backed callback manager that can be stopped gracefully: calling `stop()` must complete all currently queued callbacks (transactions, blocks, compact filters, block headers) before the returned future resolves, so no callback work is lost.

Requirements:
- The manager must implement the existing `NodeCallbacks` interface so it can be passed to `nodeConf.addCallbacks`.
- The two factory helpers that create callbacks for wallets (`CallbackUtil.createNeutrinoNodeCallbacksForWallet` and `CallbackUtil.createBitcoindNodeCallbacksForWallet`) should return the new manager instead of a raw `NodeCallbacks`; remove the `SharedKillSwitch` parameter from those methods.
- The manager must support the standard `+(other: NodeCallbacks)` combine operation.
- Update all callers (server startup code in `BitcoinSServerMain`, test helpers like `BitcoinSWalletTest.createNeutrinoNodeCallbacksForWallet`, and any related tests) to use the new return type and call `stop()` where they currently shut down the kill switch.
- Ensure that after `stop()` completes, issuing further callbacks has no effect (the manager is no longer active).

2022 07 18 node callback stream manager (#4520)


## Title: Allow local parameter bindings when `arguments` object is never accessed

## Description

Boa currently treats all simple-list parameters in non‑strict functions as “escaping” (non‑local) whenever an `arguments` object *could* be created, even if the function body never actually references `arguments`. This prevents the engine from treating those parameters as true locals, and therefore inhibits several performance optimizations (e.g., keeping parameters in registers, reducing scope lookups).

The scope analysis should be refined: if a function has a mapped arguments object (non‑strict, simple parameter list, an `arguments` binding exists) but the body **never** accesses `arguments`, the parameters should remain local bindings. Only when `arguments` is actually used should the parameters be forced to escape.

This is a performance improvement / missing optimisation, not a correctness change.

## Steps to Reproduce

Any non‑strict function with a simple parameter list and no usage of `arguments` exhibits the issue. For example:

```js
function f(a) {
  let a = 10; // shadowing let in body
  return a;
}
f(5);
```

After scope analysis, the parameter binding `a` in the function’s parameter scope is marked as non‑local (`a.local()` returns `false`), even though `arguments` is never referenced inside `f`.

## Expected Behavior

When a function’s mapped arguments object exists but is never accessed, the parameter bindings should be marked as local (i.e., `a.local()` should be `true` for the parameter binding inside the function scope).

If `arguments` *is* accessed, the current behaviour of forcing the parameters to escape should be preserved exactly as it is now.

## Additional Context / Constraints

- The logic that creates the function’s scopes and marks bindings as escaping lives in the `boa_ast` crate, particularly in the scope analysis pass and the `function_declaration_instantiation` helper.
- The engine already tracks whether the arguments object is accessed (there is a mechanism that records whether `arguments` is referenced inside the body). This information should be used to conditionally decide whether parameters must escape.
- The escape decision should not be made before the body is analysed. Instead, record that a mapped arguments object *can* exist, then after the body visit, if `arguments` was actually accessed, mark the parameter bindings as escaping. Otherwise leave them as local.
- Edge cases that affect `arguments` escaping (e.g., direct `eval`, `with` statements) must continue to be handled correctly by the existing code paths; this request only concerns the *unnecessary* pessimisation when `arguments` is never accessed.

Allow local parameters if mapped arguments object is not used (#4092)


**Title:** Implement global `EvalError` built-in
**Type:** Feature
**Priority:** Medium
**Area:** Built-ins / Error types

### Background
We have already implemented several native error constructors (`RangeError`, `TypeError`, `ReferenceError`, `SyntaxError`) and the base `Error`. The `EvalError` constructor is missing; while modern JS does not throw it, the constructor remains part of the ECMAScript standard and should be available in the global scope for compatibility.

### Request
Add the `EvalError` built-in with behaviour consistent with our existing error constructors:

- It must be accessible as a global constructor (i.e., `EvalError` in the global scope).
- The constructor accepts an optional message argument. When a message is provided, the instance’s `message` property is set accordingly.
- The constructor’s `.name` property must return `"EvalError"` and its `.length` must be `1`.
- Instances must inherit from `Error.prototype` so that `toString()` produces the expected output:
  - `new EvalError().toString()` → `"EvalError"`
  - `new EvalError("hello").toString()` → `"EvalError: hello"`
- The runtime should support constructing and throwing `EvalError`s from Rust code, following the pattern already used for other error types (i.e., corresponding methods on `Context` for `construct_eval_error` and `throw_eval_error`).
- The implementation should be integrated into the built-in initialisation sequence so that the constructor is automatically registered.

### Additional notes
- Look at how the existing error types are implemented for the expected structure and wiring.
- There is already a commented-out module for `EvalError` in the error module; that can be used as a starting point or removed, as appropriate.


As a maintainer of this JavaScript lexer, I’d like to clean up how we handle end-of-input inside the lexer. Currently the internal `preview_next` method returns `Result<char, LexerError>`, with a special “finished” error value used to signal that the input is exhausted. This forces every caller to deal with that error, and the main `lex` loop has to explicitly match on it to terminate. It also causes subtle bugs: when a source string ends without any trailing delimiter, the lexer sometimes fails to produce the last token (for example, a numeric literal at the end of a file or expression).

Please refactor the EOF handling so that `preview_next` returns `Option<char>` (returning `None` when there is no next character) and change `next_is` to return `bool` (returning `false` when there is no next character). Update the main lex loop to stop cleanly when `preview_next` returns `None`. Adjust all call sites that previously used `?` on these methods to work with the new signatures, making sure that loops and conditionals correctly break or produce a token when reaching the end.

One place where EOF should still produce an error is when a solitary `/` character appears and the next character is missing (i.e. `preview_next` returns `None` after `'/'`); return a meaningful `LexerError` there (e.g., “Expecting Token /,*,=”). No other error should be generated on normal EOF.

All existing tests should pass, and in particular number literals at the very end of the input must be lexed correctly without requiring a trailing newline or semicolon.

changing preview_next() to return Option and next_is to bool (#26)


```
Title: JSON.parse produces objects with non‑enumerable properties and parsed arrays lack a proper prototype chain

## Summary
`JSON.parse` creates data properties that are not enumerable, violating the ECMAScript spec requiring data properties to be `enumerable: true`. Additionally, arrays produced by `JSON.parse` do not inherit from `Array.prototype`, so they are missing array methods (e.g. `push`, `pop`) and object methods (e.g. `hasOwnProperty`). Finally, `Object.prototype.propertyIsEnumerable` is not implemented, making it impossible to check enumerability in a standard way.

## Steps to reproduce (conceptual)
1. Parse a JSON object: `var obj = JSON.parse('{"x": 0}');`
2. Iterate with `for...in` or call `Object.keys(obj)` – the property `"x"` should appear, but it does not.
3. Call `obj.propertyIsEnumerable("x")` – expected `true`, but the method doesn't exist or returns `false`.
4. Parse a JSON array: `var arr = JSON.parse('[1, 2]');`
5. Call `arr.push(3)` – expected to work, but fails because `push` doesn't exist.

## Expected behaviour
- Every own data property created by `JSON.parse` must be enumerable, writable, and configurable (all `true`).
- Arrays created by `JSON.parse` must have an `Array` prototype (i.e. `Array.prototype` in their prototype chain), which itself inherits from `Object.prototype`, so that all standard array and object methods are available.
- `Object.prototype.propertyIsEnumerable` should be implemented as per the ECMAScript specification, returning `true` if the given key is an own enumerable property of the object, and `false` otherwise (including when no argument is given).

## Impact
Without this fix, JSON‑parsed data cannot be reliably enumerated or used with library code that relies on standard array/object behaviour. The absence of `propertyIsEnumerable` also makes debugging and introspection harder.
```


We need basic template-literal tokenization. Backtick-delimited literals (` \`...\` `) should produce a distinct token kind. An unterminated literal (no closing backtick before end of input) must raise a lexer error. No expression interpolation is required for now; treat the entire body between backticks as a raw string value, similar to how single/double-quoted strings work.

[TemplateLiteral] Basic lexer implementation (#455)


```
Task: Remove `true`, `false`, and `null` from the keyword set and treat them as literal tokens everywhere.

Currently the engine includes `true`, `false`, and `null` as keyword entries. In ECMAScript they are not keywords but literal token types: boolean literals and the null literal. They should be removed from the keyword enumeration and handled as dedicated literal token kinds.

Observable requirements:

- The lexer must tokenise `true` and `false` directly as `BooleanLiteral` tokens, and `null` as a `NullLiteral` token, without going through keyword recognition. Any existing code that matches these strings against keyword handling must be removed so that the lexer path resolves to the literal token kinds immediately.
- Module export aliases of the form `export { ident as true }`, `export { ident as false }`, and `export { ident as null }` must continue to parse correctly. The export name parser currently relies on keyword tokens to accept these names; it must be extended to also accept the corresponding literal tokens (`BooleanLiteral` and `NullLiteral`) and map them to the same `Sym` values (`Sym::TRUE`, `Sym::FALSE`, `Sym::NULL`) that are used everywhere else in the AST.
- The grammar must not regress: all existing JavaScript constructs that use `true`, `false`, `null` should parse identically to the current behaviour.

Reference points (use these only to orient yourself):
- Keyword set: `Keyword` enum in `boa_ast`.
- Lexer: the identifier-handling code in `boa_parser` (currently resolves `true`/`false`/`null` as keyword variants before turning them into literal tokens).
- Export parser: `ModuleExportName` and `ExportSpecifier` parsing in `boa_parser` (currently match `Keyword` tokens to produce export names; these must also match the literal token kinds).

Implementation strategy:
1. Delete the `False`, `True`, and `Null` variants from the `Keyword` enum and remove all associated `as_str` / `to_sym` / `from_str` branches, test functions, and symbol mappings.
2. In the lexer’s identifier tokenisation, after collecting the identifier name, match directly on the string values `"true"`, `"false"`, `"null"` (when parsing as a keyword fails, i.e., it is not a reserved word) and produce the appropriate literal token kind. Ensure escaped characters are handled consistently by using the existing `ContainsEscapeSequence` wrapper.
3. In the module export name parser (`ModuleExportName`), after matching on `IdentifierName` and `Keyword` tokens, add two new match arms for `BooleanLiteral` and `NullLiteral` that map to `Sym::TRUE`/`Sym::FALSE` and `Sym::NULL` respectively, with `false` for the “exported as default” flag.

The change should pass all existing conformance tests and ensure `export { x as true }` etc. parse without error.
```

Remove keywords for boolean and null literals (#4113)


Currently, using the spread operator (`...`) inside a function call or a `new` expression only works correctly when the operand is a plain array. For example, `f(...[1, 2])` works, but spreading a string, a Set, a Map, or any other ECMAScript iterable either fails or produces no arguments.

The expected behavior is that `...expr` in argument position should use the standard iterator protocol, just like `for…of` and other iteration contexts in the engine. After the fix, `f(...'hello')` should call `f` with five separate arguments (`'h'`, `'e'`, `'l'`, `'l'`, `'o'`). Similarly, `new Constructor(...iterable)` should expand an arbitrary iterable.

A few additional requirements and invariants:
- Spreading a rest parameter back into a call (e.g., `g(...args)` where `args` is captured via `...args`) must still work after the change.
- The engine already has a built-in iteration module that provides `GetIterator` and an `IteratorRecord` abstraction. The fix should use that existing mechanism rather than trying to detect array-like properties.
- The parser already enforces that at most one spread argument appears in an argument list, and no further arguments follow it. The runtime expansion must respect this rule and stop evaluating subsequent arguments once a spread is encountered.
- The fix must cover both regular call expressions (`f(...x)`) and `new` expressions (`new F(...x)`), which share similar argument evaluation logic but are currently implemented in separate places. Both should behave identically with respect to iterable spreading.

Fix spread in new and call expressions (#1021)


**Title:** Trailing operators after assignment expressions are silently ignored at EOF

**Description**
When a JavaScript source file ends with a binary operator that expects a right‑hand side, the parser currently accepts the code without error. For example:
```js
var a, b = 3;
a = b +
```
…should be a syntax error (“abrupt end”), but is silently treated as though the incomplete expression does not exist.

The same problem occurs for many operators that can also form compound‑assignment operators (e.g. `*`, `/`, `%`, `|`, `&`, `^`, `||`, `==`, `===`) when they appear after an assignment or compound assignment:
```
a = b *
a /= b *
```
Trailing whitespace after the final operator must also be handled correctly.

Valid postfix increment/decrement at EOF (`a = b ++`, `a = b --`) must continue to work.

**Required behavior**

1. **Lexer – operator tokenizer**: When lexing an operator character and the next character is EOF, the lexer must not emit an error for failing to peek the next character. It should return the plain (non‑assignment) token for that operator. The parser will then encounter the missing operand and report the syntax error.
2. **Lexer – slash token**: The code that decides whether `/` starts a division or a regex must return a `Div` punctuation token when EOF follows a `/` that cannot be a regex. It must not emit an “Abrupt end” error from the lexer.
3. **Parser cursor – peek without line‑terminator skipping**: Several parser routines need to look ahead without skipping line terminators (e.g. automatic semicolon insertion, arrow‑function detection). The `Cursor` should provide a peek that does **not** skip line terminators, and those specific call sites should use it.
4. **End‑to‑end results**:
   - `a = b +` → `SyntaxError` (abrupt end)
   - `a = b + ` (trailing space) → `SyntaxError`
   - `a = b *`, `a = b /`, `a = b %`, `a = b |`, `a = b &`, `a = b ^`, `a = b ||`, `a = b ==`, `a = b ===` → `SyntaxError`
   - `a /= b *` (with/without trailing space) → `SyntaxError`
   - `a = b ++`, `a = b --` → valid, evaluates to `3` when `b=3`.

**Non‑obvious edge cases**
- Operators that are ambiguous with two‑character sequences (e.g. `**`, `||`, `??`, `<<`, `>>`, `>>>`) must still resolve correctly: when the second character is missing at EOF, the single‑character base operator must be returned.
- The change must not break semicolon insertion or arrow‑function parsing; line terminators immediately after the operator (e.g. `a = b +\n`) were already handled and must remain unaffected.

**Expected difficulty**
The fix is localised primarily in the lexer’s operator tokenizer, the slash‑token dispatch, and the parser cursor’s peek infrastructure. A targeted approach that avoids changing the overall parse error‑recovery strategy is sufficient.

bug fix: ops that stay strictly at the EOF after assigns ops are ignored (#4047)


## Feature Request: `RegExp[@@species]` getter

Add the static `Symbol.species` accessor property to the `RegExp` built-in constructor as specified in ECMAScript.

### Acceptance Criteria

1. **Property descriptor of `RegExp[Symbol.species]`**
   `Object.getOwnPropertyDescriptor(RegExp, Symbol.species)` must return a descriptor with:
   - `get`: a function
   - `set`: `undefined` (there is no setter)
   - `enumerable`: `false`
   - `configurable`: `true`

2. **Getter return value**
   The getter function, when invoked, must return its `this` value, i.e.:
   ```js
   Object.is(RegExp[Symbol.species].get.call(anyObject), anyObject) // true
   ```

3. **Getter function `name` property**
   The getter function’s `name` property must be `"get [Symbol.species]"`.
   Its own property descriptor must have:
   - `writable`: `false`
   - `enumerable`: `false`
   - `configurable`: `true`

4. **Getter function `length` property**
   The getter function’s `length` property must be `0`.
   Its own property descriptor must match the same attributes as the `name` property (i.e., `writable: false`, `enumerable: false`, `configurable: true`).

5. **Getter is not a constructor**
   Attempting to call the getter as a constructor (`new RegExp[Symbol.species].get()`) must throw a `TypeError`.


**Title:** Forward transition maps leak `WeakGc` entries for collected `SharedShape`s

**Description:**
The prototype and property forward-transition maps inside `SharedShape` hold `WeakGc<SharedShapeInner>` entries to avoid strong reference cycles. Currently those maps never remove entries whose target `SharedShapeInner` has been garbage collected. Over a long-running session this leads to unbounded memory growth because dead weak entries accumulate.

We need targeted cleanup of these maps to prevent memory leaks:

1. **Periodic pruning on insertion.** Every N insertions into a transition map (property or prototype) the map should remove all entries whose weak reference is no longer live. The threshold should be chosen to keep pruning overhead low (e.g., after every 256 insertions).

2. **Pruning on upgrade miss.** When a transition lookup is performed and the stored `WeakGc` cannot be upgraded, the dead entry should be removed immediately. This prevents repeatedly re-checking the same stale entry on future lookups.

3. Both prune paths should handle prototype and property transitions symmetrically.

**Safety / correctness invariants:**
- Pruning must never remove an entry for which the target is still reachable. The check must be exact.
- Pruning must be cheap in the common case; we shouldn’t incur a full scan every insertion.
- The existing transition lookup path (`upgrade` → `None` → create new transition) should remain correct.

**Additional infrastructure needed:**
A fast, allocation-free way to check whether a `WeakGc` is still live without performing a full upgrade and the tracing work it might trigger. This can be added as a predicate on the underlying `Ephemeron`/`WeakGc` type (e.g., `is_upgradable` or `has_value`).

**Acceptance criteria:**
- After garbage collecting a set of `SharedShape`s, their weak entries are removed from forward transition maps the next time the corresponding map is pruned (either via the periodic insertion trigger or via an upgrade miss).
- No test regressions; the existing transition sharing semantics remain unchanged.


```
Currently, `JsString::to_string_escaped` allocates a `String` every time a
string's contents are needed with proper escaping of unpaired surrogates.
This is unnecessarily expensive when the result is only used for display
(e.g. logging, error messages, debug output).

Add a way to format a `JsString` with the same escaping semantics **without
allocating** – i.e. a type that implements `Display` and writes the escaped
content directly to the formatter. The escaping must match the existing
behaviour:

- Latin‑1 strings are safe (no unpaired surrogates) and can be written
  byte‑by‑byte as `char`s.
- UTF‑16 strings must iterate code points and escape unpaired surrogates
  as `\u{XXXX}`.

To avoid duplicating the escaping logic, update `to_string_escaped` to
delegate to this new display type. Do not change the public API of
`to_string_escaped` – it should still return a `String`.
```

Add a display type for JsString to allow formatting without allocations (#3951)


**Fix `String.prototype.replace` substitution patterns and no‑match handling**

`String.prototype.replace` is broken when the first argument is a regex and the second is a replacement string containing substitution patterns (`$$`, `$&`, `` $` ``, `$'`, `$1`, `$10`, etc.) as defined in ECMAScript Table 45. Currently many of these patterns are not expanded correctly, or the implementation falls through in ways that produce wrong output. Additionally, if the regex doesn’t match the input, the method panics instead of returning the original string unchanged.

We need to make `replace` with a string replacement:

- Return the original string unmodified when the regex does **not** match.
- Correctly expand every substitution pattern listed in the spec, including:
  - `$$` → a literal `$`
  - `$&` → the matched substring
  - `` $` `` → the portion of the string before the match
  - `$'` → the portion of the string after the match
  - `$n` and `$nn` → the nth capture group (where `n` is a decimal digit or two‑digit number), with the spec rule that references ≤ 0 or greater than the number of capture groups are treated as literal text.
  - `$<` → leave a `todo!` for named capture groups, since we don’t support them yet.
- Any other `$`‑prefixed sequence that doesn’t match a recognised pattern should be treated as literal text.

The replacement must be built character by character so that patterns like `$10` are correctly recognised as a reference to capture group 10 when possible, not as `$1` followed by `0`.

Fix: String.prototype.replace substitutions, closes #610 (#629)


```
Implement `Array.prototype.flat` and `Array.prototype.flatMap`

Boa currently lacks the ES2019 methods `Array.prototype.flat` and `Array.prototype.flatMap`. Please add them following the ECMAScript specification.

Behavioral requirements:

- `flat(depth)`:
  - Default depth is 1.
  - Treat a negative depth as 0.
  - `Infinity` depth flattens all nesting levels.
  - Create a new array via `ArraySpeciesCreate` and fill it using the abstract `FlattenIntoArray` operation.

- `flatMap(callback, thisArg)`:
  - Equivalent to `.map(callback, thisArg).flat(1)`, but implemented more efficiently.
  - If `callback` is not callable, throw a `TypeError`.
  - Use the same `FlattenIntoArray` operation with depth 1 and the supplied mapper function and `thisArg`.

Common requirements:
- Both methods must work on any object with a `length` property (array‑like objects), using `ToObject`, `LengthOfArrayLike`, `Get`, and `HasProperty`.
- Holes (non‑existent indices) must be skipped like other iteration methods (e.g., `map`, `filter`).
- When writing properties into the result array, enforce that the target index stays below 2^53‑1 and throw a `TypeError` if that limit is exceeded.
- Follow the `FlattenIntoArray` abstract operation as described in the specification.

Adding these will improve Boa’s ES2019 conformance.
```


```
Title: Fix indentation of property keys in object display formatting

When displaying a JavaScript object via `value.display().to_string()` (or the
formatted output produced by `console.log` / the CLI), property keys are
currently right-aligned to the current indentation width.  This alignment
causes the output to look broken as soon as a key is longer than the indent
size (4 spaces), and it also makes the closing brace of nested objects appear
misaligned.

Example of the current (incorrect) behavior:

    {
    hello: "world",
       z: {
           a: 1
        }
    }

Notice the closing brace of the nested object is not aligned with its opening
brace, and keys are inconsistently indented across lines.

Expected behavior:

    {
        hello: "world",
        z: {
            a: 1
        }
    }

All property keys should simply be indented by a fixed number of spaces (4
spaces per nesting level), matching the standard indentation used elsewhere in
the engine’s display output.  The same rule should apply to internal
properties (e.g. `__proto__`) when they are included in the display, and to
object literals produced by the `js_object!` and similar macros.
```

Remove alignment of property keys with identation (#4390)


Implement `String.prototype.split`
Add the `split` method to the `String` prototype, conforming to the ECMAScript specification ([tc39.es/ecma262/#sec-string.prototype.split](https://tc39.es/ecma262/#sec-string.prototype.split)) and matching the behavior of modern engines.

**Signature**
`String.prototype.split(separator, limit)`

**Acceptance criteria**

1. **Basic operation**
   - The method splits the receiver string into substrings and returns an `Array` of the results.
   - If `separator` is **`undefined`** or **`null`**, the method returns an array containing the entire string as a single element, unless `limit` is `0` (see limit handling).

2. **`Symbol.split` dispatch**
   - If `separator` is an object and has a `[Symbol.split]` method, delegate to that method: call `separator[Symbol.split](string, limit)` and return its result unchanged.
   - If `separator[Symbol.split]` exists but is **not callable**, throw a `TypeError` with an appropriate message (e.g., `"separator[Symbol.split] is not a function"`).
   - If the `[Symbol.split]` property is `undefined`, proceed with the default splitting behavior as if the separator were a primitive string.

3. **Separator conversion**
   - When the default behavior is used, coerce `separator` to a string via `ToString`.
   - If the resulting string is **empty** (`""`), split the receiver into its individual UTF‑16 code units (equivalent to `.split('')`), respecting `limit`.
   - If the resulting string is non‑empty, split the receiver by occurrences of that string, respecting `limit`.

4. **Limit handling**
   - `limit` is coerced to an integer via `ToInteger`.
   - When `limit` is `0`, return an empty array regardless of the separator.
   - When `limit` is not provided, assume the maximum possible array length (`2³² − 1`).
   - The returned array must never contain more than `limit` elements.

5. **Edge cases**
   - Empty receiver `""` with empty separator `""` → `[]` (empty array).
   - Empty receiver `""` with non‑empty separator → `[""]`.
   - Non‑empty receiver with `""` separator → each character as a separate element, stopped at `limit`.
   - Splitting with a separator that does not appear in the string returns an array with the whole string.
   - Leading/trailing matches create empty string entries at the start/end (e.g., `"x1x2x".split("x")` → `["", "1", "2", ""]`).

6. **Generic `this`**
   - The method must work on non‑String objects that can be coerced to a string (via `requireObjectCoercible` then `ToString`).

The implementation should follow the patterns already established by other `String.prototype` methods in this engine (e.g., `replace`, `match`, `search`, `indexOf`) for error handling, argument processing, and array creation.


Bug report: Parser incorrectly rejects `async of` in arrow functions and for loops.

**Problem**
The JavaScript parser does not accept `async of => {}` as a valid async arrow function. In addition, writing `for (async of => {}; ; )` (a regular `for` loop whose initializer is that async arrow function) causes a syntax error: the parser complains about an invalid left-hand side expression in a `for-of` loop, even though the expression is a perfectly valid async arrow function, not a plain `async` identifier used with `of`.

**Acceptance criteria**

1. `async of => {}` must parse as an async arrow function with a single parameter named `of`. This must succeed wherever an expression is expected (module body, statement position, parenthesized, etc.).
2. The following `for` loop must parse without error, treating the async arrow function as the initializer expression:
   ```
   for (async of => {}; ; )
   ```
3. The parser must continue to reject a true `for-of` loop that uses `async` as a plain left-hand-side identifier. That is, `for (async of x)` and `for await (async of x)` must still produce a syntax error (the existing error message about an invalid left-hand side expression). This ensures we don’t accidentally silence the correct error for invalid `for-of` loops.
4. Other common `async` initializers in `for` loops (e.g. `for (async () => {}; ; )`, `for (async function() {}; ; )`) must keep working as they do today.

Fix parsing of `async` in for-of loops (#3745)


### Feature Request: DI Container Support for Console Commands

**Background**
The console `CommandRunner` currently creates command objects via direct instantiation (`new $className()`), even when the application exposes a DI container implementing `Cake\Core\ContainerInterface`. This prevents developers from writing commands that receive dependencies through their constructors, which would otherwise be resolvable by the container.

**Desired Behavior**
When resolving a command class, the `CommandFactory` should first check the application’s DI container (if available). If the container can resolve the command (i.e., `has($className)` returns true), the factory should retrieve it from the container; otherwise, it should fall back to direct instantiation. This logic must preserve full backward compatibility: commands without constructor dependencies must continue to work without changes.

The `CommandRunner` should automatically provide the container to the factory when the application implements `Cake\Core\ContainerApplicationInterface`. No additional configuration should be required from the developer beyond enabling the container in the application.

**Acceptance Criteria**

1. If a `ContainerInterface` is passed to `CommandFactory` and the container can resolve the requested command class, the container’s instance is used.
2. If the container cannot resolve the class, or no container is given, `new $className()` is used (current behavior).
3. `CommandRunner` detects whether the application is a `ContainerApplicationInterface` and passes the container to the default factory when no custom factory is explicitly provided.
4. Existing commands (including subclasses of `Shell` and implementations of `CommandInterface`) are unaffected and require no modifications.

**Relevant Interfaces & Classes**
- `Cake\Console\CommandFactory` and `Cake\Console\CommandFactoryInterface`
- `Cake\Console\CommandRunner`
- `Cake\Core\ContainerInterface` and `Cake\Core\ContainerApplicationInterface`


As a developer building a CakePHP application, I want a simpler way to manage plugins so that I can work with them as a straightforward collection of objects, rather than through a class‑name–resolving registry.

**Acceptance criteria:**

1. **Plugins are added as fully instantiated objects.**
   - I can create a plugin object myself and insert it into the plugin container.
   - The container does not resolve class names or instantiate plugins on its own.

2. **Container provides a standard collection interface.**
   - I can add a plugin, remove it by name, check if a named plugin exists, and retrieve a plugin by name.
   - The container is iterable (`foreach`) and countable.
   - Attempting to `get()` a plugin that hasn't been added throws an exception.

3. **Plugins self‑report their identity.**
   - Every plugin has a `getName()` method that returns its full name including vendor namespace (e.g. `"Company/TestPluginThree"`).
   - The container keys plugins by this name.

4. **Plugins expose which hooks they have enabled.**
   - Each plugin indicates whether it wants its routing, bootstrap, middleware, and console hooks invoked via methods like `isRoutesEnabled()`, `isBootstrapEnabled()`, `isMiddlewareEnabled()`, `isConsoleEnabled()`.
   - The standard plugin class provides enable/disable toggles for all four hooks.

5. **The container can filter plugins by a hook name.**
   - I can call a filter method with a string like `'routes'`, `'bootstrap'`, `'middleware'`, or `'console'`.
   - It returns only those plugins that have the corresponding hook enabled.
   - Passing an unrecognized hook name throws an exception.

6. **No event dispatching on plugin load.**
   - The container does not fire events when a plugin is added; it is a dumb container.

7. **The previous registry is removed in favour of this collection.**
   - Application bootstrap, routing, middleware, and console integration should rely on this collection instead of the old `PluginRegistry`.
   - The old `PluginRegistry` (which resolved class names and dispatched events) is eliminated.

Convert PluginRegistry into a Collection.


Add deprecation warnings to `getModelType()` and `setModelType()` in `ModelAwareTrait`.

`ModelAwareTrait` is already documented as deprecated since 4.3.0, but typical usage (e.g., `loadModel()`, magic model property access, or direct calls to the type methods) does not currently emit any deprecation notice. Add `deprecationWarning()` calls to `getModelType()` and `setModelType()` so that any code path that triggers loading or configuring model type will produce a deprecation warning. The message should point developers toward `ORM\LocatorAwareTrait` or datasource-specific registries.

This will cause all external use of `loadModel()` and property-level autoloading to raise deprecation errors, which is the intended push to migrate away from the generic model-aware trait. Directly deprecating `loadModel()` itself is deferred because the method is used extensively internally and needs a more careful approach (e.g., only deprecating non-ORM usage). For now, the deprecation of the type accessor effectively flags external model loading as deprecated.

4.5 Add deprecations for most of ModelAwareTrait


**Feature Request: Add SQL-standard `FILTER` clause support to aggregate expressions**

### User Story
As a developer using the query builder, I want to apply a conditional filter directly on an aggregate function so that I can write concise `COUNT(...) FILTER (WHERE ...)` or `SUM(...) FILTER (WHERE ...)` expressions without resorting to subqueries or CASE workarounds.

### Acceptance Criteria

1. **Callable on aggregate functions**
   Any aggregate expression (e.g. returned by `$query->func()->count('*')`, `$query->func()->sum('amount')`, etc.) exposes a `filter()` method that accepts conditions in the same formats as `Query::where()` (array, string, `ExpressionInterface`, or `Closure`).

2. **SQL output**
   When the aggregate expression is converted to SQL, and a filter has been set, the output must include:
   `FILTER (WHERE <conditions>)`
   immediately after the function call, and **before** any `OVER` clause if a window is also defined.
   - Example: `COUNT(*) FILTER (WHERE status = 'active') OVER ()`

3. **Combining multiple filter calls**
   Calling `filter()` more than once on the same expression must combine the conditions with `AND`, producing a single `FILTER (WHERE (cond1 AND cond2))` in the output.

4. **Absence of filter**
   If `filter()` is never called, no `FILTER` clause is emitted in the SQL.

5. **Cloning**
   Cloning an aggregate expression must also clone its internal filter expression, so that modifications to the clone do not affect the original.

6. **Traversal**
   When the aggregate expression is traversed (e.g., for visitor-based transformations), the filter expression must be visited and traversed before the window expression (if any).

### Constraints & Compatibility
- The `FILTER` clause must be generated exactly as `FILTER (WHERE ...)` (standard SQL).
- The feature must not break existing code that doesn’t use the filter.
- The filter must be compatible with window clauses (`OVER`, `PARTITION BY`, etc.) on the same aggregate expression.
- Database compatibility requirement: the generated SQL should be valid on PostgreSQL and SQLite ≥ 3.30.0, which support the `FILTER` clause natively. (No expectation to emulate this on other drivers.)

Added FILTER () clause support to aggregate functions.


Extend `SchemaDialect` with public schema reflection methods so that migrations and other components that already have a dialect instance can query table lists and table metadata without needing a `Collection`.

Acceptance criteria:
- `SchemaDialect` gains three new public methods: `listTables(): array<string>`, `listTablesWithoutViews(): array<string>`, and `describe(string $name): TableSchemaInterface`.
- `listTables()` returns all tables and views accessible in the current connection.
- `listTablesWithoutViews()` returns only base tables (no views).
- `describe(string $name)` returns a full `TableSchemaInterface` for the given table name. The name may include a schema prefix in `schema.table` form. The returned schema must include columns, indexes, foreign keys, and table options. If no columns are found for the table, `describe()` must throw a `DatabaseException`.
- The existing `Collection` class (and by extension `CachedCollection`) delegates to the dialect’s new methods, preserving its current behavior and caching semantics exactly.
- The reflection SQL generation (e.g., `listTablesSql`, `describeColumnSql`, etc.) remains unchanged and continues to be the basis for the dialect’s new runtime methods.

Move several schema reflection methods to Dialect


The `PostgresSchemaDialect` is missing the new reflection methods required by CakePHP’s refreshed schema API. After the 5.2 update, attempting to call `$dialect->describeColumns('articles')`, `$dialect->describeIndexes('articles')`, or `$dialect->describeForeignKeys('articles')` results in a fatal error because these methods are not implemented in the PostgreSQL driver.

This blocks any code that wants low-level access to column/index/foreign key metadata directly (e.g., for custom schema diff tools or introspection utilities) and forces callers to work only through the older `SchemaCollection->describe()` path, which suffers from subtle data quality issues.

**Observed problems when reflecting a PostgreSQL table with the current code:**

1. **Columns are duplicated** – the same column may appear multiple times in the meta-data, likely due to the join with `pg_attribute` even though `DISTINCT` is used.
2. **Column ordering is unreliable** – the ordering does not consistently match the physical `ordinal_position` of the columns on the table.
3. **Missing serial/auto-increment detection** – columns defined as `SERIAL` or `BIGSERIAL` are not flagged with `'autoIncrement' => true`.
4. **Boolean defaults returned as strings** – instead of proper numeric/boolean values, the default for a boolean column comes back as the string `'true'` or `'false'`.
5. **Precision handling absent for timestamp and numeric types** – `TIMESTAMP(precision)` columns lose their precision entirely, and `NUMERIC(precision, scale)` columns may have incorrect or missing `length` and `precision` values.
6. **Multi-column foreign keys are garbled** – when a foreign key constraint spans multiple columns, the referenced column order is not preserved and may be returned as a flat list instead of correctly ordered arrays.

The expected behavior is that:
- `describeColumns()` returns an array of column definitions **exactly once** per column, in `ordinal_position` order, with correct handling of serial, boolean defaults, and precision.
- `describeIndexes()` returns index/unique definitions with columns in the correct order.
- `describeForeignKeys()` returns foreign key definitions that preserve the column ordering on both the local and referenced sides; when a FK includes only a single column, the backward-compatible string format is respected.
- All three methods work against the schema/table configured in the connection, falling back to `'public'` when no schema is specified.

The patch should reuse the existing `describeColumnSql`, `describeIndexSql`, and `describeForeignKeySql` logic (since those queries already return the right data) but add the three new `describe*()` methods that consume the results and produce properly normalized arrays, mimicking what other dialects already provide. Duplication must be eliminated, ordering must be guaranteed, and the column conversion logic must handle serials, boolean defaults, and precision correctly.


Add a `load` method to `AssociationCollection` that creates and registers an association in one call.
Signature: `load(string $className, string $associated, array $options = []): Association`

- Instantiates `$className` with `$associated` and `$options`.
- If `tableLocator` is not present in `$options`, default to the collection’s own locator.
- Validates that the created object is an instance of `Cake\ORM\Association`; throw `InvalidArgumentException` if it is not.
- Adds the association to the collection keyed by its name (the name the association reports).
- Return the added association.


**Title:** `WindowExpression` needs `PARTITION BY` and `ORDER BY` support

Currently `WindowExpression` only produces `OVER ()` and the `partition()` / `order()` methods inherited from `WindowInterface` are not implemented. This prevents any practical use of window functions with partitioning or ordering.

**Requested behaviour:**

- Implement `partition($partitions)` so it accepts:
  - a single string (treated as a column identifier),
  - an `IdentifierExpression`,
  - any other `ExpressionInterface` object,
  - an array mixing these types.
  Repeated calls should merge partitions, not replace them.

- Implement `order($fields)` so it matches the conventions of `OrderByExpression` / `Query::order()`: a string field, an associative array of `'field' => 'DIRECTION'`, etc. Internally it should build an `OrderByExpression`. Repeated calls should append to the ordering.

- `sql()` must generate a clause that includes `PARTITION BY` only, `ORDER BY` only, or both combined, producing strings like:
  - `OVER (PARTITION BY col)`
  - `OVER (ORDER BY col)`
  - `OVER (PARTITION BY col ORDER BY col2 DESC)`
  When neither partitions nor order are set, an empty `OVER ()` must still be returned.

- Empty inputs (`''`, `[]`, `null`-ish) to either method should leave the window expression unchanged and not alter the generated SQL.

- `traverse()` must pass all partitions and the internal `OrderByExpression` to the visitor so that value binding and expression tree walking work correctly.

- The other `WindowInterface` methods (`range`, `rows`, `groups`, `exclude*`) can remain as no-op stubs (`return $this`) for now; they are out of scope.

**Why this matters:**

The `AggregateExpression` already supports `->over()` and appends a window clause. Once `WindowExpression` can carry real partition/order definitions, developers can use window functions like `ROW_NUMBER() OVER (PARTITION BY department ORDER BY salary DESC)` directly.

Implemented partition() and order() for WindowExpression


We need a way to restrict a `Route` to a specific set of HTTP methods after construction, with validation and a fluent interface.

**User story:** As a developer building routes programmatically, I want to call a dedicated setter on a `Route` instance to declare the allowed HTTP methods, so that I can avoid embedding method constraints in the constructor defaults and catch invalid method names early.

**Acceptance criteria:**

1. A new public method `setMethods(array $methods)` is available on `Route`.
2. The method accepts an array of string method names (e.g., `['get', 'post']`) in any casing and normalizes them to uppercase.
3. Only the standard HTTP methods are permitted: `GET`, `PUT`, `POST`, `PATCH`, `DELETE`, `OPTIONS`, `HEAD`. If any provided method name is not in that set, an `InvalidArgumentException` is thrown with a message that includes the invalid name(s).
4. Calling `setMethods()` updates the route’s internal `_method` configuration so that the route subsequently matches only requests whose HTTP method is one of the given methods (matching behavior identical to defining `_method` via the legacy `[method]` defaults key).
5. The setter returns `$this` to allow method chaining.
6. The constructor’s existing support for `[method]` in defaults must continue to work as before (the `[method]` key is converted to `_method`), but this is legacy behavior and should not interfere with the new API.


Update the `upgrade` command to handle moving locale files in addition to templates.

Currently the command only supports moving `src/Template` to `templates` when invoked with the `templates` argument.
We need to add support for moving locale files from `src/Locale` to `resources/locales` for both the application and all plugins.

**Behavior:**
- The command should accept a required positional argument `type` with values `templates` or `locales`.
- When type is `locales`:
  - For the application: move `src/Locale` → `resources/locales`.
  - For every plugin path (like current template logic): recursively find any directory that ends with `/Locale` (i.e., a folder named `Locale` inside the plugin’s `src`), and move its contents up one level into `resources/locales` relative to the plugin root. The resulting plugin directory structure should have `resources/locales/<files>` and an empty or removed `src/Locale`.
- The `rename` helper should create the destination’s parent directory if it does not exist before performing the move (whether via git or filesystem rename).
- The `--dry-run` option should default to `true` (boolean).

Update UpgradeCommand to handle locale files moving.