Repository: apache/dubbo
File: dubbo-rpc/dubbo-rpc-triple/src/main/java/org/apache/dubbo/rpc/protocol/tri/stream/AbstractTripleClientStream.java (Java)

Code before:
     */
    protected abstract void consumeBytes(int numBytes);

    @Override
    public boolean isReady() {
        Channel channel = streamChannelFuture.getNow();
        if (channel == null) {
            return false;
        }
        return channel.isWritable();
    }

    /**
     * Called when the channel writability changes.
     * This method should be invoked by the transport handler when channelWritabilityChanged is triggered.
     * It synchronously notifies the listener (TripleClientCall) which is responsible for
     * asynchronously triggering all necessary callbacks through its executor.
     */
    protected void onWritabilityChanged() {
        notifyOnReady(false);
    }

    /**
     * Called by InitOnReadyQueueCommand to trigger the initial onReady notification.
     */
    public void triggerInitialOnReady() {
        notifyOnReady(true);
    }

    /**
     * notify listener when stream becomes ready
     *
     * @param forceNotify if true, always trigger onReady (for initial notification);
     *                    if false, only trigger when state changes from "not ready" to "ready"
     */
    private void notifyOnReady(boolean forceNotify) {
        boolean wasReady = lastReadyState;
        boolean isNowReady = isReady();
        lastReadyState = isNowReady;

        // Trigger onReady if:
        // 1. forceNotify is true (initial notification, spurious is OK), or
        // 2. state changes from "not ready" to "ready"
        if (forceNotify || (!wasReady && isNowReady)) {
            listener.onReady();
        }
    }

    class ClientTransportListener extends AbstractH2TransportListener implements H2TransportListener {

        private TriRpcStatus transportError;

Review comment (suggestion):
The triggerInitialOnReady method should be package-private or protected rather than public since it's only called by InitOnReadyQueueCommand within the same package. Public visibility exposes internal stream state management that should not be accessible to external clients.
```suggestion
    void triggerInitialOnReady() {
```

Code after:
    protected abstract void consumeBytes(int numBytes);

    @Override
    public boolean isReady() {
        Channel channel = streamChannelFuture.getNow();
        if (channel == null) {
            return false;
        }
        return channel.isWritable();
    }

    /**
     * Called when the channel writability changes.
     * This method should be invoked by the transport handler when channelWritabilityChanged is triggered.
     * It synchronously notifies the listener (TripleClientCall) which is responsible for
     * asynchronously triggering all necessary callbacks through its executor.
     */
    protected void onWritabilityChanged() {
        notifyOnReady(false);
    }

    /**
     * Called by InitOnReadyQueueCommand to trigger the initial onReady notification.
     */
    public void triggerInitialOnReady() {
        notifyOnReady(true);
    }

    /**
     * notify listener when stream becomes ready
     *
     * @param forceNotify if true, always trigger onReady (for initial notification);
     *                    if false, only trigger when state changes from "not ready" to "ready"
     */
    private synchronized void notifyOnReady(boolean forceNotify) {
        boolean wasReady = lastReadyState;
        boolean isNowReady = isReady();
        lastReadyState = isNowReady;

        // Trigger onReady if:
        // 1. forceNotify is true (initial notification, spurious is OK), or
        // 2. state changes from "not ready" to "ready"
        if (forceNotify || (!wasReady && isNowReady)) {
            listener.onReady();
        }
    }

    class ClientTransportListener extends AbstractH2TransportListener implements H2TransportListener {

        private TriRpcStatus transportError;
        private DeCompressor decompressor;