Skip to content

Harden Inertia request state and SSR lifecycle - #487

Merged
binaryfire merged 10 commits into
0.4from
audit/inertia-correctness-parity-lifecycle
Aug 7, 2026
Merged

Harden Inertia request state and SSR lifecycle#487
binaryfire merged 10 commits into
0.4from
audit/inertia-correctness-parity-lifecycle

Conversation

@binaryfire

@binaryfire binaryfire commented Aug 7, 2026

Copy link
Copy Markdown
Collaborator

Summary

This PR completes the Inertia correctness and SSR lifecycle maintenance work for Hypervel's long-lived worker model.

The main changes are:

  • preserve provider-boot Inertia configuration as an immutable baseline and clone it into each request coroutine;
  • keep mutable scroll-prop resolution local to each request and prop path;
  • correct version, Vary, empty-response, falsey identifier, numeric prop-key, and initial-page JSON behavior;
  • make the Inertia page payload authoritative when rendering the root view;
  • validate SSR responses before constructing the result and distinguish transport failures from page-local render failures;
  • retain the reusable SSR client and worker-wide transport backoff without allowing remote payloads to control breaker state;
  • make SSR start and stop commands report real process and server outcomes while preserving Node, Bun, and custom runtime support;
  • reuse the existing page-finder cache through one container identity;
  • document SSR operation, configuration, failure handling, and the raw-client testing seam.

Request state

Provider boot may configure shared props, the root view, asset versions, SSR exclusions, and related defaults before request coroutines exist. That state now lives as one non-coroutine baseline. The first Inertia access inside a request shallow-clones the baseline into coroutine context.

This keeps boot configuration available while preventing one request's page, shared props, SSR result, or runtime configuration from leaking into another request. Mutable ScrollProp instances are cloned at the resolver boundary because their callback result and merge metadata are request-specific. Arbitrary user-owned prop objects are left alone.

Protocol behavior

Middleware now applies Vary: X-Inertia to the response that is actually returned and deduplicates the value case-insensitively. Version-mismatch location responses include the current asset version header. Only an exact empty response body triggers empty-response handling, so "0", streamed responses, and binary responses are preserved.

Initial-page serialization now fails through the normal JSON exception path instead of silently emitting an empty payload. When SSR succeeds, the fallback page JSON is no longer encoded a second time. Root view data can no longer replace the framework-owned page value and make directives disagree with components.

The remaining identifier and header boundaries use exact null and empty-string checks. This preserves valid "0" values and numeric top-level prop keys without broad coercion changes elsewhere.

SSR lifecycle

The gateway keeps one cookie-free Guzzle client so successful renders continue to reuse connections. Successful HTTP contact clears transport backoff. Connection failures and malformed transport responses arm it; structured page-render failures do not suppress unrelated pages.

Successful payloads are accepted only when they contain a string body and an array of string head entries. Remote error metadata is normalized before events are constructed, and remote error types are never treated as authority over worker state.

The development hot URL may be configured directly with INERTIA_SSR_HOT_URL, or read from Vite's hot file. If that file disappears between publication checks, rendering falls back to the client without creating a synthetic SSR failure.

inertia:start-ssr now uses Hypervel's coroutine-aware signal handling and returns the child process result. inertia:stop-ssr performs a bounded health check, requests shutdown through the concrete gateway, and distinguishes an unavailable server from a rejected shutdown. The response-less close used by the official SSR endpoint remains supported.

Compatibility and performance

No supported Inertia method, named argument, prop type, middleware contract, helper, command option, runtime, or protected extension point is removed.

The existing performance design remains intact: immutable metadata stays worker-cached, SSR keeps a reusable connection, and the page finder reuses its successful lookup cache. Added request work is limited to bounded in-memory checks and the shallow copies required for isolation. Successful SSR removes the previous second full-page JSON encoding.

Current upstream DevTools support is intentionally left for the next Inertia work unit so it can be designed and reviewed independently.

Validation

  • focused Inertia tests, including coroutine isolation, middleware, response, prop resolution, SSR gateway, and command behavior;
  • the complete Inertia package suite;
  • composer fix, covering formatting, static analysis, the parallel component suite, Testbench package mode, and dogfood checks;
  • final API, caller/callee, lifecycle, failure-path, and hot-path review.

For more details, see: docs/plans/2026-08-07-2018-inertia-correctness-ssr-lifecycle-and-current-parity.md

Summary by CodeRabbit

  • New Features

    • Added configurable Inertia SSR hot URL support through environment configuration.
    • Improved SSR server health checks, shutdown handling, retry backoff, and client-side fallback behavior.
    • Enhanced request isolation to prevent shared state and scroll properties from leaking between requests.
    • Improved handling of numeric, empty, and falsey prop values.
  • Bug Fixes

    • Corrected SSR failure reporting and malformed-response handling.
    • Prevented duplicate Vary: X-Inertia headers.
    • Preserved custom response headers and error-bag values more reliably.
  • Documentation

    • Expanded SSR configuration, HTTP client, testing, and runtime behavior documentation.

Replicate provider-boot defaults into a request-local InertiaState and route every state consumer through that owner. Centralize SSR dispatch, keep the resolved page authoritative, and prevent view data from replacing framework protocol data.

Make component and directive fallback JSON failures explicit, avoid duplicate page encoding after successful SSR, preserve exact root identifiers and integer prop keys, and cover boot inheritance, sibling isolation, dispatch identity, and rendering equivalence.
Resolve each mutable ScrollProp through its own shallow copy so boot-shared values, sibling requests, and repeated logical paths cannot share cached results or merge metadata. Memoize legitimate null results while retaining retry behavior after exceptions.

Preserve falsey helper, merge, once, reset, and diagnostic values; use strict protocol-list membership; normalize numeric keys only where string paths are required; and correct the affected return and owner annotations. Add regressions for nested providers, numeric-looking header collisions, metadata ownership, and null resolution.
Attach the current asset version to mismatch redirects, append and case-insensitively deduplicate Vary on the response actually returned, and preserve existing cache variance through replacement responses.

Treat only exact empty-string content as an empty response so zero, streamed, and binary bodies remain intact. Preserve zero-valued error-bag names and use strict redirect-method matching, with coverage for normal responses and every replacement path.
Give the gateway contract and concrete transport one worker identity, retain the reusable cookie-free client, and singleton-reuse the existing page finder cache. Add configurable hot URLs with checked publication fallback and normalize provider container resolution.

Validate the exact SSR success shape, normalize remote error metadata, and limit worker backoff to connection and malformed-transport failures while clearing it on proven reachability. Add handler-independent health and shutdown transport behavior with comprehensive success, failure, backoff, identity, cache, and configuration coverage.
Replace process-global PCNTL handlers with the inherited coroutine-scoped signal registry while retaining Node, Bun, and absolute runtime selection. Return failure for unsuccessful child exits instead of reporting every completed process as success.

Make the stop command verify server health through the shared transport before shutdown, distinguish refusal from the normal response-less close, and return standard console outcomes. Cover runtime arguments, signal cleanup, child exits, health failures, returned statuses, and closed shutdown connections.
Add concise Laravel-style method docblocks to the exception response and facade extension surfaces without changing behavior or visibility.

Complete the missing void return types in the bundle detector tests so the touched package test surface follows the repository typing conventions.
Document runtime selection, configurable hot URLs, transport timeouts, bounded worker backoff, client-rendered fallback, failure events, and throw-on-error behavior in the canonical Vite guide using Laravel-style prose.

Keep the package README minimal while recording the public raw-client testing seam and standardizing the upstream reference. Complete the Vite table of contents and keep the starter-kit note attached to the start command.
Capture the final request-state, prop ownership, protocol, SSR transport, command lifecycle, documentation, performance, testing, and compatibility decisions in the focused implementation plan.

Update the core routing index and durable ledger with inertia-01 through inertia-23, completed validation and review evidence, rejected machinery, the revalidated support boundary, and the current upstream DevTools surface reserved as the next work unit. Keep the package checklist open until DevTools lands.
…ess-parity-lifecycle

# Conflicts:
#	docs/plans/2026-07-12-0915-framework-coroutine-state-lifecycle-audit-ledger.md
@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@binaryfire, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 41 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 85b38f80-8e3f-4f7c-83c7-429a0282cbb3

📥 Commits

Reviewing files that changed from the base of the PR and between 84485e9 and 7cb14c4.

📒 Files selected for processing (1)
  • tests/Inertia/HttpGatewayTest.php
📝 Walkthrough

Walkthrough

The Inertia package now centralizes coroutine-local state and SSR dispatch. It tightens response, prop, and transport handling, updates SSR commands and container bindings, and adds documentation plus regression tests for lifecycle isolation and falsey values.

Changes

Inertia lifecycle and SSR parity

Layer / File(s) Summary
Audit plan and documented contracts
docs/plans/*, src/boost/docs/vite.md, src/inertia/README.md
The audit and implementation plan document Inertia lifecycle, SSR, transport, container, command, and parity decisions. The documentation describes SSR configuration, hot URLs, backoff, client isolation, and testing.
Replicated state and rendering flow
src/inertia/src/InertiaState.php, src/inertia/src/Directive.php, src/inertia/src/Response.php, src/inertia/src/ResponseFactory.php, src/inertia/src/View/Components/*, src/inertia/src/helpers.php, src/inertia/src/ExceptionResponse.php, src/inertia/src/Inertia.php, tests/Inertia/{CoroutineIsolation,Component,Directive,Helper,Response,ResponseFactory,BundleDetector}Test.php
InertiaState now provides replicated coroutine state, instance-based cached SSR dispatch, and boot-baseline inheritance. Rendering paths use the current state, throw on invalid JSON, preserve falsey IDs, and keep generated page data authoritative.
Protocol boundaries and prop resolution
src/inertia/src/Middleware.php, src/inertia/src/PropsResolver.php, src/inertia/src/ScrollProp.php, src/inertia/src/MergesProps.php, src/inertia/src/ResponseFactory.php, src/inertia/src/Middleware/EnsureGetOnRedirect.php, tests/Inertia/{Middleware,PropsResolver,ScrollProp,MergeProp,SsrRenderFailed}Test.php
Middleware now manages Vary and version headers without duplication. Prop resolution uses strict path checks, preserves falsey keys, clones mutable scroll props, and caches successful null results without caching failures.
SSR transport and hot URL handling
src/inertia/config/inertia.php, src/inertia/src/Ssr/*, tests/Inertia/HttpGatewayTest.php
SSR dispatch validates head and body, distinguishes structured render failures from transport failures, manages backoff, normalizes metadata, supports configured or Vite hot URLs, and exposes shutdown handling.
Container bindings and SSR commands
src/inertia/src/InertiaServiceProvider.php, src/inertia/src/Commands/*, tests/Inertia/{InertiaServiceProvider,Commands/StartSsr,Commands/StopSsr}Test.php
The gateway and view finder use singleton container bindings. SSR commands use command signal traps, report child-process status, perform health checks, and report shutdown outcomes.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Request
  participant InertiaState
  participant ViewComponent
  participant HttpGateway
  participant SSRServer
  Request->>InertiaState: current()
  ViewComponent->>InertiaState: set page and dispatchSsr()
  InertiaState->>HttpGateway: dispatch SSR request
  HttpGateway->>SSRServer: render page
  SSRServer-->>HttpGateway: validated head/body or failure
  HttpGateway-->>InertiaState: cached response or failure event
  InertiaState-->>ViewComponent: SSR response or JSON fallback
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 34.64% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the PR's main changes to Inertia request state management and SSR lifecycle behavior.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch audit/inertia-correctness-parity-lifecycle

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@greptile-apps

greptile-apps Bot commented Aug 7, 2026

Copy link
Copy Markdown

Greptile Summary

This PR hardens Inertia request isolation, protocol handling, SSR transport validation, and SSR process lifecycle behavior.

  • Establishes a provider-boot state baseline that is cloned into request coroutine context.
  • Tightens response, prop-resolution, serialization, and SSR payload contracts.
  • Adds SSR health, shutdown, transport-backoff, runtime, and operational documentation changes.

Confidence Score: 4/5

The PR is not yet safe to merge because the stop command can still claim success when the shutdown request fails and the SSR server remains running.

The separate health request does not prove that the subsequent shutdown request was accepted, yet StopSsr swallows every transport exception and immediately reports that the server stopped.

Files Needing Attention: src/inertia/src/Commands/StopSsr.php; tests/Inertia/Commands/StopSsrTest.php

Important Files Changed

Filename Overview
src/inertia/src/Commands/StopSsr.php Adds a health preflight and gateway shutdown orchestration, but still reports success for all shutdown transport failures.
src/inertia/src/Ssr/HttpGateway.php Adds validated SSR response handling, transport-specific backoff, hot-file fallback, health checks, and a reusable-client shutdown request.
src/inertia/src/InertiaState.php Introduces a provider-boot baseline replicated into coroutine-local request state.
src/inertia/src/PropsResolver.php Isolates mutable scroll-prop resolution and corrects numeric prop-path handling.
src/inertia/src/Middleware.php Corrects returned-response variance, version headers, empty-response detection, and strict protocol boundaries.
tests/Inertia/Commands/StopSsrTest.php Covers health and shutdown outcomes but incorrectly treats every shutdown transport exception as a successful response-less close.

Reviews (2): Last reviewed commit: "test(inertia): clarify malformed respons..." | Re-trigger Greptile

Comment thread src/inertia/src/Commands/StopSsr.php

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (2)
src/inertia/src/InertiaServiceProvider.php (2)

28-53: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Type all changed container factory callback parameters.

The production and test bindings omit native types for container callback parameters. Verify the container callback contract, then declare the supported types.

  • src/inertia/src/InertiaServiceProvider.php#L28-L53: type the $app parameters in both singleton() factory callbacks.
  • tests/Inertia/Commands/StartSsrTest.php#L30-L35: type the factory callback parameters used by bind(Process::class, ...).

As per coding guidelines, “use native types for parameters, return values, and properties wherever permitted.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/inertia/src/InertiaServiceProvider.php` around lines 28 - 53, Type the
container factory callback parameters according to the supported container
callback contract. In src/inertia/src/InertiaServiceProvider.php lines 28-53,
add native types to the $app parameters of both singleton factory callbacks; in
tests/Inertia/Commands/StartSsrTest.php lines 30-35, type the factory callback
parameters used by bind(Process::class, ...). Preserve the existing binding
behavior.

Source: Coding guidelines


28-31: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Type the container factory callback parameters.

fn ($app) and function ($app) in the singleton factory callbacks should have their container parameters typed. Use the supported container type, and use Application if this service provider receives the application instance from Hypervel’s ServiceProvider::app.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/inertia/src/InertiaServiceProvider.php` around lines 28 - 31, Update the
singleton factory callback in InertiaServiceProvider to type its $app parameter
with the supported container type, using Application if ServiceProvider::app
provides that instance. Preserve the existing Gateway::class binding and
HttpGateway::class resolution.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/inertia/src/Commands/StopSsr.php`:
- Around line 36-45: Update the TransferException handling in the StopSsr
command’s gateway->shutdown() flow so transport failures are not automatically
treated as successful shutdowns. After the expected connection close, verify the
SSR server is unhealthy before returning success; otherwise report the exception
through the command error path and return self::FAILURE, while preserving the
existing handling for a false shutdown result.

In `@src/inertia/src/Inertia.php`:
- Around line 48-50: Update the PHPDoc description for getFacadeAccessor() to
state that it returns the Inertia facade accessor or service binding, replacing
the inaccurate description about a registered component name.

In `@tests/Inertia/HttpGatewayTest.php`:
- Around line 182-205: Extend
testMalformedSuccessDispatchesFailureAndHonorsThrowOnError with a separate
disabled-throwing case: reset the gateway state, set inertia.ssr.throw_on_error
to false, configure a malformed successful SSR response, and assert dispatch
returns null without throwing. Avoid relying on the existing backoff-active
second dispatch, and preserve the current throwing assertion.
- Around line 247-251: Update the listed hot-file tests to configure Vite with a
test-owned disposable path via Vite::useHotFile(...) before createHotFile(...),
rather than writing to the default public hot path. Track and delete only that
temporary path during teardown, preserving each test’s existing assertions and
hot-file behavior.

---

Nitpick comments:
In `@src/inertia/src/InertiaServiceProvider.php`:
- Around line 28-53: Type the container factory callback parameters according to
the supported container callback contract. In
src/inertia/src/InertiaServiceProvider.php lines 28-53, add native types to the
$app parameters of both singleton factory callbacks; in
tests/Inertia/Commands/StartSsrTest.php lines 30-35, type the factory callback
parameters used by bind(Process::class, ...). Preserve the existing binding
behavior.
- Around line 28-31: Update the singleton factory callback in
InertiaServiceProvider to type its $app parameter with the supported container
type, using Application if ServiceProvider::app provides that instance. Preserve
the existing Gateway::class binding and HttpGateway::class resolution.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: f9c3fea1-1905-4c74-961b-9212b8e24e61

📥 Commits

Reviewing files that changed from the base of the PR and between b75e579 and 84485e9.

📒 Files selected for processing (42)
  • docs/plans/2026-07-12-0900-framework-coroutine-state-lifecycle-audit.md
  • docs/plans/2026-07-12-0915-framework-coroutine-state-lifecycle-audit-ledger.md
  • docs/plans/2026-08-07-2018-inertia-correctness-ssr-lifecycle-and-current-parity.md
  • src/boost/docs/vite.md
  • src/inertia/README.md
  • src/inertia/config/inertia.php
  • src/inertia/src/Commands/StartSsr.php
  • src/inertia/src/Commands/StopSsr.php
  • src/inertia/src/Directive.php
  • src/inertia/src/ExceptionResponse.php
  • src/inertia/src/Inertia.php
  • src/inertia/src/InertiaServiceProvider.php
  • src/inertia/src/InertiaState.php
  • src/inertia/src/MergesProps.php
  • src/inertia/src/Middleware.php
  • src/inertia/src/Middleware/EnsureGetOnRedirect.php
  • src/inertia/src/PropsResolver.php
  • src/inertia/src/Response.php
  • src/inertia/src/ResponseFactory.php
  • src/inertia/src/ScrollProp.php
  • src/inertia/src/Ssr/HttpGateway.php
  • src/inertia/src/Ssr/SsrException.php
  • src/inertia/src/Ssr/SsrRenderFailed.php
  • src/inertia/src/View/Components/App.php
  • src/inertia/src/View/Components/Head.php
  • src/inertia/src/helpers.php
  • tests/Inertia/BundleDetectorTest.php
  • tests/Inertia/Commands/StartSsrTest.php
  • tests/Inertia/Commands/StopSsrTest.php
  • tests/Inertia/ComponentTest.php
  • tests/Inertia/CoroutineIsolationTest.php
  • tests/Inertia/DirectiveTest.php
  • tests/Inertia/HelperTest.php
  • tests/Inertia/HttpGatewayTest.php
  • tests/Inertia/InertiaServiceProviderTest.php
  • tests/Inertia/MergePropTest.php
  • tests/Inertia/MiddlewareTest.php
  • tests/Inertia/PropsResolverTest.php
  • tests/Inertia/ResponseFactoryTest.php
  • tests/Inertia/ResponseTest.php
  • tests/Inertia/ScrollPropTest.php
  • tests/Inertia/SsrRenderFailedTest.php

Comment thread src/inertia/src/Commands/StopSsr.php
Comment thread src/inertia/src/Inertia.php
Comment thread tests/Inertia/HttpGatewayTest.php
Comment thread tests/Inertia/HttpGatewayTest.php
Document why the second malformed-response dispatch is load-bearing.\n\nThe assertion proves transport backoff is armed before throw_on_error raises the SSR exception, so the queued follow-up response must remain untouched.
@binaryfire

Copy link
Copy Markdown
Collaborator Author

@coderabbitai @greptile-apps I reviewed every main-thread, inline, nitpick, and pre-merge finding against the current Inertia server, Guzzle transport behavior, Hypervel's container conventions, and the Testbench runtime.

One change was made: the malformed-response regression now explains that its second dispatch proves transport backoff was armed before throw_on_error raised the exception. The disabled-throw path was already covered by the malformed-response data provider.

The remaining suggestions do not require changes:

  • StopSsr keeps its handler-independent health preflight. In the official clustered server, the serving worker closes before the primary kills its siblings, so an immediate follow-up health request can falsely fail a successful shutdown. Guzzle does not provide a portable exception-class distinction between that empty reply and other connection failures.
  • The facade docblock keeps the canonical wording used throughout Hypervel and its facade documentation.
  • The hot-file tests already write inside Testbench's disposable process-owned application clone. Moving the path through Vite::useHotFile() would add shared instance state without improving isolation.
  • Container factory callbacks retain the established provider convention. An Application hint would also be narrower than the container object that invokes factories.
  • The generic docstring-percentage warning does not match this repository's Laravel-style documentation rules.

The focused regression and complete Inertia package suite are green. The follow-up is in 7cb14c42d.

@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

git show --stat --oneline --decorate --no-renames 7cb14c42d
git show --format=fuller --no-ext-diff --unified=80 7cb14c42d -- \
  tests/Inertia/HttpGatewayTest.php \
  src/inertia/src/Ssr/HttpGateway.php \
  src/inertia/src/Commands/StopSsr.php \
  src/inertia/src/Inertia.php \
  src/inertia/src/InertiaServiceProvider.php

ast-grep outline tests/Inertia/HttpGatewayTest.php --items all --type function --match 'testMalformedSuccessDispatchesFailureAndHonorsThrowOnError|malformedSsrResponses'
ast-grep outline src/inertia/src/Commands/StopSsr.php --items all
ast-grep outline src/inertia/src/InertiaServiceProvider.php --items all

Length of output: 8890


@binaryfire The update in 7cb14c42d is correct.

The second dispatch and the one-request assertion prove that malformed-response handling arms transport backoff before throw_on_error raises SsrException. The data provider covers the non-throwing path.

I accept the remaining decisions. The StopSsr health preflight, Testbench hot-file setup, container factory callback type, facade wording, and Laravel-style documentation policy do not require changes.

🐇 ✓


✏️ Learnings added
Learnt from: binaryfire
URL: https://github.com/hypervel/components/pull/487

Timestamp: 2026-08-07T23:43:14.651Z
Learning: In `src/inertia/src/Commands/StopSsr.php`, retain the handler-independent SSR health preflight. In the official clustered SSR server, the serving worker can close before the primary worker stops sibling workers. Therefore, an immediate post-shutdown health check can report a false failure. Guzzle does not provide a portable exception class that distinguishes this expected empty reply from other connection failures.

Learnt from: binaryfire
URL: https://github.com/hypervel/components/pull/487

Timestamp: 2026-08-07T23:43:14.651Z
Learning: In `tests/Inertia/HttpGatewayTest.php`, SSR hot-file tests write to Testbench’s disposable, process-owned application clone. Do not replace this with `Vite::useHotFile()`, because that adds shared Vite instance state without improving test isolation.

Learnt from: binaryfire
URL: https://github.com/hypervel/components/pull/487

Timestamp: 2026-08-07T23:43:14.651Z
Learning: In `src/inertia/src/InertiaServiceProvider.php`, container factory callbacks follow the established provider convention and should retain the container parameter type. Do not narrow the callback parameter to `Application`, because the factory is invoked by the container object.

Learnt from: binaryfire
URL: https://github.com/hypervel/components/pull/487

Timestamp: 2026-08-07T23:43:14.651Z
Learning: For Hypervel facade documentation, retain the canonical wording used throughout Hypervel facade documentation. Do not request generic docstring-percentage changes when they conflict with the repository’s Laravel-style documentation rules.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.


If you found this review helpful, would you consider giving us a shout-out on X?

Thank you for using CodeRabbit!

You are interacting with an AI system.

@greptile-apps

greptile-apps Bot commented Aug 7, 2026

Copy link
Copy Markdown

The follow-up commit lands cleanly. The added comment in testMalformedSuccessDispatchesFailureAndHonorsThrowOnError makes the ordering constraint explicit — // Backoff must be armed before throw_on_error raises the exception. immediately precedes the assertNull that would silently pass even if backoff hadn't fired, so the intent is now unambiguous to any future reader.

The reasoning on the declined suggestions holds:

  • StopSsr health preflight — the clustered-server ordering issue is real and Guzzle's exception hierarchy doesn't give a portable way to distinguish an empty-reply close from other transport failures, so the handler-independent check is the correct approach.
  • Facade docblock — keeping canonical wording is the right call for consistency across the codebase.
  • Hot-file test isolationVite::useHotFile() would introduce shared singleton state; the subclass override used in HotFileRemovedHttpGateway is cleaner and more targeted.
  • Container factory Application hint — narrowing the type would be less accurate than the container object the factory actually receives.
  • Docstring percentage — doesn't apply to Laravel-style documentation conventions in this repo.

The test suite additions look thorough: the data-provider coverage of malformed SSR shapes, the backoff semantics split across testRemoteConnectionErrorDoesNotActivateTransportBackoff, testConnectionFailureActivatesTransportBackoff, and testMalformedSuccessActivatesTransportBackoff together document the exact distinction the gateway enforces between transport failures and page-render failures. testInFlightSuccessClearsTransportBackoff covers the race that would otherwise be invisible.

Good to merge.

@binaryfire
binaryfire merged commit 0848a9c into 0.4 Aug 7, 2026
38 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant