Skip to content

Complete View correctness, lifecycle, and Laravel parity - #477

Merged
binaryfire merged 17 commits into
0.4from
audit/view-correctness-lifecycle-parity
Aug 6, 2026
Merged

Complete View correctness, lifecycle, and Laravel parity#477
binaryfire merged 17 commits into
0.4from
audit/view-correctness-lifecycle-parity

Conversation

@binaryfire

@binaryfire binaryfire commented Aug 6, 2026

Copy link
Copy Markdown
Collaborator

Summary

This change completes a correctness, lifecycle, and current Laravel parity pass over the View package.

It gives compiler and render state explicit ownership in long-lived workers, makes inline component publication durable, fixes compiled-view freshness and cleanup, restores current component and compiler APIs, and corrects View configuration and split-package metadata. It also ports the current full-application View integration coverage and updates the public documentation for worker-lived compiled views.

No useful Laravel-facing API is removed. Hypervel keeps its alias-first component registration and worker-singleton View architecture while making transient state coroutine-safe.

For more details, see: docs/plans/2026-08-06-0916-view-correctness-lifecycle-and-current-parity.md

Compiler and render lifecycles

The View Factory and Blade compiler remain worker-lived singletons. Transient sections, footers, raw blocks, echo overrides, render stacks, components, slots, loops, and compiled paths are owned by the active coroutine or compile pass.

This includes:

  • resetting current-section state at each compilation boundary;
  • restoring nested and exceptional echo-format overrides exactly;
  • clearing retained slot, component, and loop state after rendering;
  • rendering mutable View section content before storing it in copied coroutine context;
  • preserving lazy View defaults when a section already exists;
  • releasing compiled-path diagnostic state through finally on success and failure;
  • restoring current protected compiler hooks and provider extension points.

The parent-placeholder format now uses one immutable worker salt and a compiler v3 marker. Superseded context maps, properties, helpers, and compiled output are removed rather than retained behind compatibility paths.

Components and compiled views

Inline component templates are published through the existing atomic filesystem replacement boundary. Existing files are accepted only when their exact size matches, so empty templates remain valid while zero-byte and partial artifacts are repaired.

Component lookup keys use fixed-size xxh128 digests, and the reserved component namespace is replaced instead of accumulating stale paths. Compiled views memoize only paths already verified fresh, continue to honor disabled caching, recover when a previously verified file is deleted, and retain the normal one-check-per-worker fast path.

Component attributes, nested conventional components, unnamed slots, backed-enum dynamic component names, conditional stack directives, named arguments, exception metadata, and generated facades now match their current supported contracts.

Configuration and package boundaries

Foundation now publishes the complete View compiler defaults with user-facing configuration comments. The View provider consumes those canonical values without duplicate fallbacks.

The split package declares the Symfony packages it uses directly, removes false Foundation and Validation requirements, and keeps Foundation as an optional suggestion for generated Vite and font directives. Dead validation middleware and its dependency are removed.

The view:cache command now deduplicates canonical roots by directory boundary. Nested roots are compiled once, while path-prefix siblings and filesystem roots remain correct.

Performance

The request render path gains no lock, retry, poll, watcher, network call, serialization layer, or container-resolution loop. New context operations occur at compilation and cleanup boundaries. Echo formatting adds one constant-time context read per escaped echo during compilation, not during rendered-view execution.

Inline component hashing is a fast fixed-size digest performed before the existing static lookup is populated. Filesystem validation occurs only when publishing an uncached inline template. Cache-root normalization runs only in the deployment-time command.

Verification

  • composer fix
  • focused View and full-application View integration coverage
  • Foundation View configuration and command coverage
  • Mail Markdown coroutine coverage
  • facade generation and linting
  • strict split-package Composer validation
  • both PHPStan configurations after review amendments
  • git diff --check

Summary by CodeRabbit

  • New Features

    • Added configurable compiled-view caching, hashing, file extensions, and timestamp checks.
    • Improved Blade components with dynamic enum-based names, custom paths, nested components, slots, and safer inline-view publication.
    • Added more reliable rendering across concurrent requests and long-running workers.
  • Bug Fixes

    • Fixed view, loop, section, echo-format, and cache cleanup between renders.
    • Improved directive parsing, component resolution, style merging, and recovery from missing or stale compiled views.
  • Documentation

    • Expanded view caching guidance and documented framework differences and worker behavior.

Publish inline Blade templates through the existing atomic filesystem replacement boundary, accept only exact file sizes, and repair missing or partial artifacts without rejecting legitimate empty templates. Bound retained component lookup keys with xxh128 and replace the reserved component namespace instead of accumulating stale paths.

Add counterfactual coverage for atomic publication, complete-file cache hits, empty and truncated files, fixed-size keys, namespace replacement, cache reuse, and static cache cleanup.
Bring component attributes, slots, dynamic component names, and nested conventional component discovery in line with the current Laravel-facing contracts. Terminate existing style defaults correctly, expose accurate exception metadata, accept backed enum component names, and default unnamed slots without weakening strict compiler paths.

Port focused coverage for style merging, nested component class resolution, unnamed slots, and enum-backed dynamic component rendering while retaining Hypervel component registration semantics.
Give transient section, footer, raw-block, and echo-format state explicit compile-pass and coroutine ownership while retaining worker-level compiler defaults. Restore current protected compiler contracts, immutable parent placeholders, conditional stack parsing, strict token handling, and the compiler v3 cache boundary without locks, clones, or request-scoped services.

Memoize only verified-fresh compiled views and release the compiled-path stack through finally on every success or failure path. Add deterministic coverage for sequential and concurrent compilation, nested and exceptional echo overrides, Mail compilation, footer and directive extension hooks, cache-disabled recompilation, deleted files, and diagnostic cleanup.
Flush component slots, slot stacks, and loop frames with the Factory state they belong to so failed renders cannot retain slot content or corrupt later loop metadata. Preserve eager rendering only when a mutable View becomes stored section content, and keep yield defaults lazy when a section already exists.

Add regressions for retained slot state, failed-render loop cleanup, uncountable loops, copied coroutine contexts, unused View defaults, strict loop identity, named arguments, and the existing request-shared-data lifecycle.
Publish the complete compiler configuration in Foundation, consume those canonical values without duplicate provider fallbacks, and restore public provider registration extension points. Use consistent container resolution in the edited provider closures and document worker-lived resolver and compiler mutators at their actual lifecycle boundaries.

Restore finder named-argument parity and add focused coverage for provider visibility, resolver replacement, canonical configuration defaults, finder behavior, and split application configuration merging.
Declare the Symfony contracts View uses directly, remove false Foundation and Validation requirements, and retain Foundation only as an optional integration for generated Vite and font directives. Delete the unused validation middleware rather than carrying dead source and a dependency solely for it.

Add manifest coverage that keeps split Symfony constraints aligned with the monorepo root, verifies deliberate dependency omissions and suggestions, and pins provider discovery in both package and root metadata.
Regenerate the Blade and View facade method annotations from the corrected concrete APIs. The generated surface now reflects the supported stringable callback domain and static parent placeholder contract while removing the superseded Hypervel-only placeholder getter.

Keeping these generated files in their own commit makes the mechanical public metadata update easy to compare with the source changes that produced it.
Canonicalize view cache roots, collapse trailing-separator duplicates, and reject only true descendants at a directory boundary. Preserve filesystem roots and path-prefix siblings so deployment-time compilation neither duplicates nested trees nor drops unrelated directories.

Use consistent make-based View resolution throughout the command and add counterfactual coverage for nested roots, prefix siblings, missing paths, duplicate separators, and a filesystem root containing a nested view directory.
Port the current full-application Blade, anonymous component, and renderable exception scenarios into package-scoped Hypervel integration tests. Include the complete template fixture set for components, slots, scoped includes, dynamic calls, alternate extensions, appendable attributes, and exception rendering.

The integration surface also exercises configured Blade extensions and cache-root deduplication through the real application container while preserving Hypervel bootstrap and coroutine conventions.
Explain compiled-view freshness in worker terms, recommend deployment-time view caching, and describe when live workers require an explicit cache clear after local edits. Keep the user guidance in Laravel-style prose without exposing coroutine-context or internal cache implementation details.

Update the package README with its documentation and upstream references plus the two public Hypervel differences developers need to account for: alias-first component registration and eager rendering when a View becomes stored section content.
Record the signed-off View design, findings, rejected machinery, performance boundaries, test strategy, and final implementation state. Close the package checklist and routing index while carrying the completed view-01 and reflection-02 revalidations and the Foundation and Translation cross-package ownership entries.

The records distinguish retained slot memory from loop-output corruption, document the Xdebug-only parser branch without a synthetic seam, and leave no View TODO, deferred defect, compatibility workaround, or open workflow step.
@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 19d6ac39-fca1-4714-8dae-172b6f1cdbb2

📥 Commits

Reviewing files that changed from the base of the PR and between af9929f and 0df83b3.

📒 Files selected for processing (5)
  • docs/plans/2026-07-12-0915-framework-coroutine-state-lifecycle-audit-ledger.md
  • docs/plans/2026-08-06-0916-view-correctness-lifecycle-and-current-parity.md
  • src/view/src/Compilers/BladeCompiler.php
  • tests/View/Blade/BladeComponentsTest.php
  • tests/View/ViewBladeCompilerTest.php
🚧 Files skipped from review as they are similar to previous changes (1)
  • docs/plans/2026-07-12-0915-framework-coroutine-state-lifecycle-audit-ledger.md

📝 Walkthrough

Walkthrough

This PR completes a View lifecycle audit. It adds coroutine-safe compiler and render-state cleanup, compiled-view cache configuration, component publication fixes, dependency updates, API corrections, documentation, and extensive View integration and regression tests.

Changes

View lifecycle and correctness

Layer / File(s) Summary
Configuration and service wiring
src/foundation/config/view.php, src/foundation/src/Console/ViewCacheCommand.php, src/view/src/ViewServiceProvider.php, src/view/composer.json
Adds compiled-view cache options, canonicalizes cache paths, updates service resolution, changes provider visibility, and aligns package dependencies.
Coroutine-safe compiler state
src/view/src/Compilers/*, src/view/src/Engines/*
Scopes sections, footers, raw blocks, echo formats, and compiled paths to coroutine state. Cleanup runs after successful and failed rendering.
Components, layouts, directives, and loops
src/view/src/Component.php, src/view/src/Compilers/ComponentTagCompiler.php, src/view/src/Concerns/*, src/view/src/DynamicComponent.php
Updates component lookup, slot defaults, dynamic component names, layout placeholders, loop cleanup, directive parsing, inline-view hashing, and atomic publication.
Documentation and public contracts
src/boost/docs/views.md, src/view/README.md, src/support/src/Facades/*
Documents worker-level compiled-view reuse and updates facade annotations and placeholder naming.
Regression and integration coverage
tests/View/*, tests/Integration/View/*, tests/Foundation/*, tests/Mail/MarkdownCoroutineSafetyTest.php
Adds coverage for cache freshness, coroutine isolation, component rendering, anonymous components, compiler cleanup, package metadata, and nested Markdown rendering.

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

Sequence Diagram(s)

sequenceDiagram
  participant ViewFactory
  participant CompilerEngine
  participant BladeCompiler
  participant CoroutineContext
  ViewFactory->>CompilerEngine: Render view
  CompilerEngine->>BladeCompiler: Compile or reuse compiled view
  BladeCompiler->>CoroutineContext: Store temporary state
  CompilerEngine->>ViewFactory: Return rendered output
  CompilerEngine->>CoroutineContext: Clear compiled-path state
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 52.81% 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
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the PR's main focus on View correctness, lifecycle behavior, and Laravel parity.
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.
✨ 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/view-correctness-lifecycle-parity

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 6, 2026

Copy link
Copy Markdown

Greptile Summary

This PR completes a broad View-package correctness and Laravel-parity pass while adapting transient compiler and render state to Hypervel’s long-lived coroutine workers.

  • Isolates and exhaustively cleans transient Blade compilation and rendering state.
  • Corrects compiled-view freshness, inline-component publication, component behavior, directive parsing, and cache-root handling.
  • Restores View configuration, extension APIs, package metadata, test cleanup ownership, documentation, and integration coverage.

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains.

Important Files Changed

Filename Overview
src/view/src/Compilers/BladeCompiler.php Adds compile-pass ownership and cleanup, directive argument parsing, component publication safeguards, and restored compiler extension APIs without an eligible unresolved finding.
src/view/src/Engines/CompilerEngine.php Adds verified-fresh memoization, deleted-compiled-file recovery, and exhaustive compiled-path cleanup consistent with the documented worker-lifetime cache model.
src/view/src/Factory.php Extends render-state cleanup so transient component, slot, and loop state does not remain in coroutine context.
src/view/src/Concerns/ManagesComponents.php Corrects component and slot lifecycle cleanup after rendering.
src/view/src/Concerns/ManagesLayouts.php Revises parent-placeholder and section storage behavior while preserving lazy defaults.
src/foundation/src/Console/ViewCacheCommand.php Deduplicates canonical view roots by directory boundaries without conflating path-prefix siblings.
src/testbench/src/PHPUnit/TestCase.php Assigns caller-dependent exception-handler restoration to the raw Testbench base while preserving exhaustive teardown.
src/testing/src/PHPUnit/AfterEachTestSubscriber.php Centralizes framework static-state cleanup and includes the newly standardized View reset hooks.
src/view/src/ViewServiceProvider.php Consumes canonical View configuration and restores provider extension points and engine wiring.
src/view/composer.json Corrects direct split-package dependencies and removes false Foundation and Validation requirements.

Reviews (3): Last reviewed commit: "fix(view): clear compile-pass state on f..." | Re-trigger Greptile

@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: 5

🧹 Nitpick comments (1)
src/support/src/Facades/Blade.php (1)

48-48: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Import Closure for this annotation.

Line 48 uses the fully qualified \Closure name. Add use Closure; and use Closure|string in the annotation. The source rule requires imports instead of fully qualified class names outside configuration-style identifier lists.

🤖 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/support/src/Facades/Blade.php` at line 48, Update the Blade facade
annotations by importing Closure with a use statement and changing the
stringable method annotation to use Closure|string instead of the fully
qualified \Closure name.

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/view/src/Component.php`:
- Line 156: Update the Component class by adding a public flushState(): void
method at the end, with the exact docblock title “Flush all static state.” Clear
every static cache and reference there, including
static::$ignoredParameterNames, while preserving the existing flushCache()
behavior.

In `@src/view/src/Engines/CompilerEngine.php`:
- Around line 52-83: At the end of the CompilerEngine class, add the public
static flushState(): void API with the exact docblock title “Flush all static
state.” and reset the compiledOrNotExpired static cache. Preserve
forgetCompiledOrNotExpired() as a compatibility wrapper by having it delegate to
flushState() rather than removing it.

In `@src/view/src/FileViewFinder.php`:
- Around line 52-62: Restore the public find() parameter name to $name in both
ViewFinderInterface and FileViewFinder so named calls using find(name: ...)
remain compatible. Update the method body and its calls to findNamespacedView()
and findInPaths() consistently, preserving the existing lookup behavior.

In `@tests/Integration/View/BladeTest.php`:
- Around line 257-270: Move HelloComponent from
tests/Integration/View/BladeTest.php lines 257-270 into a Fixtures file under
the Hypervel\Tests\Integration\View\BladeTest namespace. Move
RenderableException from tests/Integration/View/RenderableViewExceptionTest.php
lines 34-40 into a Fixtures file under the
Hypervel\Tests\Integration\View\RenderableViewExceptionTest namespace, and
update the view fixture that instantiates it to use the new namespace.

In `@tests/View/Blade/BladePushTest.php`:
- Around line 89-100: Update parseConditionalStackExpression() to split the
directive arguments at the final top-level comma, preserving commas inside the
stack argument and condition expressions; replace the current explode()-based
parsing and add a test covering `@pushIf`(true, 'body,end') with the expected
compiled output.

---

Nitpick comments:
In `@src/support/src/Facades/Blade.php`:
- Line 48: Update the Blade facade annotations by importing Closure with a use
statement and changing the stringable method annotation to use Closure|string
instead of the fully qualified \Closure name.
🪄 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: 745a4acb-8fa6-49f3-b4e6-41e2cbcda36d

📥 Commits

Reviewing files that changed from the base of the PR and between 457fa11 and 2eb29d1.

📒 Files selected for processing (78)
  • 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-06-0916-view-correctness-lifecycle-and-current-parity.md
  • src/boost/docs/views.md
  • src/foundation/config/view.php
  • src/foundation/src/Console/ViewCacheCommand.php
  • src/support/src/Facades/Blade.php
  • src/support/src/Facades/View.php
  • src/view/README.md
  • src/view/composer.json
  • src/view/src/Compilers/BladeCompiler.php
  • src/view/src/Compilers/Compiler.php
  • src/view/src/Compilers/ComponentTagCompiler.php
  • src/view/src/Compilers/Concerns/CompilesConditionals.php
  • src/view/src/Compilers/Concerns/CompilesContexts.php
  • src/view/src/Compilers/Concerns/CompilesEchos.php
  • src/view/src/Compilers/Concerns/CompilesErrors.php
  • src/view/src/Compilers/Concerns/CompilesLayouts.php
  • src/view/src/Compilers/Concerns/CompilesSessions.php
  • src/view/src/Component.php
  • src/view/src/ComponentAttributeBag.php
  • src/view/src/ComponentSlot.php
  • src/view/src/Concerns/ManagesComponents.php
  • src/view/src/Concerns/ManagesLayouts.php
  • src/view/src/Concerns/ManagesLoops.php
  • src/view/src/DynamicComponent.php
  • src/view/src/Engines/CompilerEngine.php
  • src/view/src/Engines/EngineResolver.php
  • src/view/src/Factory.php
  • src/view/src/FileViewFinder.php
  • src/view/src/Middleware/ValidationExceptionHandle.php
  • src/view/src/View.php
  • src/view/src/ViewServiceProvider.php
  • tests/Foundation/Console/ViewCacheCommandTest.php
  • tests/Foundation/FoundationConfigTest.php
  • tests/Integration/View/BladeAnonymousComponentTest.php
  • tests/Integration/View/BladeTest.php
  • tests/Integration/View/RenderableViewExceptionTest.php
  • tests/Integration/View/anonymous-components-1/app.blade.php
  • tests/Integration/View/anonymous-components-2/buttons/danger.blade.php
  • tests/Integration/View/anonymous-components-2/panel.blade.php
  • tests/Integration/View/anonymous-components-templates/page.blade.php
  • tests/Integration/View/templates/components/appendable-panel.blade.php
  • tests/Integration/View/templates/components/base-input.blade.php
  • tests/Integration/View/templates/components/child-input.blade.php
  • tests/Integration/View/templates/components/hello-span.blade.php
  • tests/Integration/View/templates/components/input-with-slot.blade.php
  • tests/Integration/View/templates/components/link.blade.php
  • tests/Integration/View/templates/components/menu-item.blade.php
  • tests/Integration/View/templates/components/menu.blade.php
  • tests/Integration/View/templates/components/panel.blade.php
  • tests/Integration/View/templates/consume.blade.php
  • tests/Integration/View/templates/different-extension.sh
  • tests/Integration/View/templates/hello.blade.php
  • tests/Integration/View/templates/partials/scoped-partial.blade.php
  • tests/Integration/View/templates/renderable-exception.blade.php
  • tests/Integration/View/templates/uses-appendable-panel.blade.php
  • tests/Integration/View/templates/uses-child-input.blade.php
  • tests/Integration/View/templates/uses-include-regular.blade.php
  • tests/Integration/View/templates/uses-include-scoped.blade.php
  • tests/Integration/View/templates/uses-link.blade.php
  • tests/Integration/View/templates/uses-panel-dynamically.blade.php
  • tests/Integration/View/templates/uses-panel.blade.php
  • tests/Integration/View/templates/varied-dynamic-calls.blade.php
  • tests/Mail/MarkdownCoroutineSafetyTest.php
  • tests/View/Blade/BladeComponentTagCompilerTest.php
  • tests/View/Blade/BladePushTest.php
  • tests/View/ComponentTest.php
  • tests/View/DynamicComponentTest.php
  • tests/View/PackageMetadataTest.php
  • tests/View/ViewBladeCompilerTest.php
  • tests/View/ViewCompilerEngineTest.php
  • tests/View/ViewComponentAttributeBagTest.php
  • tests/View/ViewEngineResolverTest.php
  • tests/View/ViewFactoryTest.php
  • tests/View/ViewFileViewFinderTest.php
  • tests/View/ViewServiceProviderTest.php
  • tests/View/ViewTest.php
💤 Files with no reviewable changes (1)
  • src/view/src/Middleware/ValidationExceptionHandle.php

Comment thread src/view/src/Component.php
Comment thread src/view/src/Engines/CompilerEngine.php
Comment thread src/view/src/FileViewFinder.php
Comment thread tests/Integration/View/BladeTest.php
Comment thread tests/View/Blade/BladePushTest.php
Replace comma-based Blade directive splitting with a shared top-level parser backed by PHP's tokenizer. The parser keeps commas inside strings, interpolation, arrays, calls, attributes, and other nested expressions while retaining the cheap path for expressions without commas.

Apply the corrected boundary to conditional stacks, once-only push and prepend directives, and @JSON. This preserves JSON_HEX defaults and explicit depth, keeps generated IDs correct, and prevents malformed compiled output for nested expressions.

Add focused regressions for literal and nested commas, interpolated strings, generated once IDs, and JSON encoding options. The work remains compilation-only and adds no render-time path.
Give Component and CompilerEngine standard flushState hooks and route framework test cleanup through them. Component cache cleanup now covers ignored parameter metadata as well as reflection and Blade caches while retaining the narrower production reset APIs.

Keep internal cleanup and metadata methods out of component template data, synchronize the documented reserved names, and pin the exact public component data surface. Complete the touched component/compiler method metadata and slot-context return type.

Add focused coverage for every static field, both CompilerEngine reset entry points, and the component exposure boundary so future worker-global additions cannot silently escape cleanup or become callable from templates.
Remove Testbench Foundation Application's duplicate registry of framework static resets. The authoritative after-test subscriber already owns those resets, and keeping a second list allowed the two registries to drift.

Move the one caller-dependent reset into the raw Testbench PHPUnit base: exception-handler restoration requires the active test case. Its teardown now retains the earliest failure while still performing Mockery verification and cleanup, matching the Components base lifecycle.

Remove redundant test teardown calls, retain only test-owned resource cleanup, and extend the shared failure regression to prove both base cases still verify and close Mockery when handler restoration throws.
Extend the View findings through view-40 for directive parsing, static cleanup, internal component exposure, and touched method metadata. Record the final ownership model, rejected parser and lifecycle machinery, compile-time-only cost, and upstream-ready Blade defects.

Route the genuine Boost, Foundation, Testbench, and Testing implications through the dependency index and completed-package records. Mark implementation, validation, self-review, and independent code review complete with no deferred View issue or stale in-progress wording.
@binaryfire

Copy link
Copy Markdown
Collaborator Author

@coderabbitai Thanks for the review. The follow-up is pushed in four focused commits.

Implemented:

  • Added complete Component and CompilerEngine static reset hooks, routed the global test subscriber through them, and pinned every static field plus the component template-data boundary.
  • Replaced comma-based Blade parsing with a shared top-level tokenizer for conditional stacks, once-only stacks, and @json. The regressions cover nested commas, interpolation tokens, generated IDs, and preservation of JSON safety flags. This runs during template compilation only.
  • Removed Testbench's duplicate framework cleanup registry. The raw Testbench base now owns the one caller-dependent exception-handler reset and preserves the first teardown failure while still verifying Mockery.
  • Updated the public reserved-name list and durable audit records.

Two suggestions were intentionally not applied:

  • FileViewFinder::find keeps the view parameter because that is the current Laravel API, and a named-argument regression pins it.
  • The two integration-test helpers remain inline because each is unique to one test file and no namespace collision exists; splitting them into fixture files would add structure without solving a problem.

The full repository gate was green before the bounded review amendments. Focused View and lifecycle coverage, the Testbench package suite, formatting, and the final diff checks are green after them.

@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown

Tip

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

@binaryfire Thanks for the detailed follow-up.

The reset hooks, tokenizer coverage, and Testbench cleanup address the reported concerns. The retained FileViewFinder::find(string $view) parameter is appropriate for Laravel API parity. The inline test helpers are also appropriate for their current isolated use.

Thanks for completing the focused validation.

🐇 ✅


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

Timestamp: 2026-08-06T13:47:45.699Z
Learning: In `src/view/src/FileViewFinder.php`, `FileViewFinder::find` must use the parameter name `$view` to preserve the current Laravel named-argument API. A named-argument regression test protects this contract.

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.

@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: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/view/src/Compilers/BladeCompiler.php (1)

252-253: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Clear raw-block state when compilation fails.

Line 252 resets last-section state and Line 253 resets footer state. It does not reset RAW_BLOCKS_CONTEXT_KEY. If compilation fails after storeUncompiledBlocks() and before restoreRawContent(), raw template content remains in the active coroutine. A later compileString() call can reuse and grow that stale stack.

Initialize the raw-block context before compilation. Clear it in a finally block after compilation completes or fails.

🤖 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/view/src/Compilers/BladeCompiler.php` around lines 252 - 253, Update the
BladeCompiler compilation flow around CoroutineContext initialization and
cleanup: initialize RAW_BLOCKS_CONTEXT_KEY before compilation, and clear it in a
finally block so both successful and failed compilation remove any stored raw
blocks. Preserve the existing last-section and footer context resets, and anchor
the cleanup to compileString() and the
storeUncompiledBlocks()/restoreRawContent() flow.
🧹 Nitpick comments (1)
docs/plans/2026-08-06-0916-view-correctness-lifecycle-and-current-parity.md (1)

552-557: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Add a malformed-nesting regression test.

Line 248 defines fail-loud behavior when tokenizer nesting is malformed. The focused test list covers commas and tokenizer-combined openers, but it does not cover malformed nesting. Add a case that verifies the expression remains unsplit and fails at the normal compilation boundary.

🤖 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 `@docs/plans/2026-08-06-0916-view-correctness-lifecycle-and-current-parity.md`
around lines 552 - 557, Add a malformed-tokenizer-nesting regression case to the
focused Blade compiler tests covering the fail-loud behavior defined around line
248: assert the expression remains unsplit and compilation fails at the normal
compilation boundary. Place it with the existing comma and tokenizer-combined
opener cases.
🤖 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 `@docs/plans/2026-08-06-0916-view-correctness-lifecycle-and-current-parity.md`:
- Line 138: Update the Blade stringable() compatibility documentation to remove
the claim that its accepted input was narrowed, or explicitly describe the
change as non-narrowing. Ensure it reflects that Laravel’s closure registration
form remains supported and Fluent::class remains valid as a string, while
keeping the statement that no useful Laravel-facing API is removed.

---

Outside diff comments:
In `@src/view/src/Compilers/BladeCompiler.php`:
- Around line 252-253: Update the BladeCompiler compilation flow around
CoroutineContext initialization and cleanup: initialize RAW_BLOCKS_CONTEXT_KEY
before compilation, and clear it in a finally block so both successful and
failed compilation remove any stored raw blocks. Preserve the existing
last-section and footer context resets, and anchor the cleanup to
compileString() and the storeUncompiledBlocks()/restoreRawContent() flow.

---

Nitpick comments:
In `@docs/plans/2026-08-06-0916-view-correctness-lifecycle-and-current-parity.md`:
- Around line 552-557: Add a malformed-tokenizer-nesting regression case to the
focused Blade compiler tests covering the fail-loud behavior defined around line
248: assert the expression remains unsplit and compilation fails at the normal
compilation boundary. Place it with the existing comma and tokenizer-combined
opener cases.
🪄 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: 3085edf6-bac5-44e9-b613-d6e602933806

📥 Commits

Reviewing files that changed from the base of the PR and between 2eb29d1 and af9929f.

📒 Files selected for processing (27)
  • 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-06-0916-view-correctness-lifecycle-and-current-parity.md
  • src/boost/docs/blade.md
  • src/foundation/src/Bootstrap/HandleExceptions.php
  • src/testbench/src/Foundation/Application.php
  • src/testbench/src/PHPUnit/TestCase.php
  • src/testing/src/PHPUnit/AfterEachTestSubscriber.php
  • src/view/src/Compilers/BladeCompiler.php
  • src/view/src/Compilers/ComponentTagCompiler.php
  • src/view/src/Compilers/Concerns/CompilesConditionals.php
  • src/view/src/Compilers/Concerns/CompilesJson.php
  • src/view/src/Compilers/Concerns/CompilesStacks.php
  • src/view/src/Component.php
  • src/view/src/Concerns/ManagesComponents.php
  • src/view/src/Engines/CompilerEngine.php
  • tests/Testbench/CreatesApplicationTest.php
  • tests/Testbench/Foundation/ApplicationTest.php
  • tests/Testbench/Foundation/Bootstrap/CreateVendorSymlinkTest.php
  • tests/Testbench/TestCaseTest.php
  • tests/Testing/Concerns/InteractsWithMockeryTest.php
  • tests/View/Blade/BladeJsonTest.php
  • tests/View/Blade/BladePrependTest.php
  • tests/View/Blade/BladePushTest.php
  • tests/View/ViewCompilerEngineTest.php
  • tests/View/ViewComponentTest.php
  • tests/View/ViewStaticStateTest.php
💤 Files with no reviewable changes (5)
  • tests/Testbench/Foundation/Bootstrap/CreateVendorSymlinkTest.php
  • tests/Testbench/CreatesApplicationTest.php
  • tests/Testbench/Foundation/ApplicationTest.php
  • tests/Testbench/TestCaseTest.php
  • src/testbench/src/Foundation/Application.php
🚧 Files skipped from review as they are similar to previous changes (6)
  • src/view/src/Compilers/ComponentTagCompiler.php
  • src/view/src/Compilers/Concerns/CompilesConditionals.php
  • tests/View/ViewCompilerEngineTest.php
  • src/view/src/Concerns/ManagesComponents.php
  • 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

Initialize raw Blade blocks at the start of each compilation and release raw-block and component-hash state in a finally block. This prevents caught compiler failures and incomplete component compilations from retaining template bytes or hash frames in coroutine or fallback process context.\n\nPreserve Laravel's public component-hash seed contract by leaving entry-time hashes intact for the immediately following compile pass, while ensuring they cannot survive that pass. Add load-bearing success and failure regressions that preserve the original exception, prove fresh subsequent compilation, and retain the seed-then-compile sequence.\n\nRecord view-41, the bounded lifecycle contract, validation, and final review status in the View plan and audit ledger.
@binaryfire

Copy link
Copy Markdown
Collaborator Author

@coderabbitai Follow-up is in 0df83b32b.

The raw-block finding was correct. BladeCompiler::compileString() now initializes raw-block state at pass entry and clears raw blocks and component-hash frames in finally after success or failure. Component hashes intentionally remain available at entry because the public newComponentHash() API can seed the immediately following pass; exit cleanup bounds that state without breaking the Laravel sequence. Regression coverage pins caught failures, exception identity, fresh subsequent compilation, successful opening-only cleanup, and seed-then-compile behavior.

The stringable() wording is also clarified. The supported class-string-plus-handler and typed-closure forms remain intact; this is a corrected contract description, not a runtime API change.

I did not add the malformed-nesting nitpick. compileString() generates PHP but does not execute it. Malformed input already remains unsplit and fails at the normal PHP execution boundary, while existing incomplete-expression coverage protects the parser branch. An additional eval-level test would duplicate PHP behavior rather than add a distinct View invariant.

Focused and complete View coverage, static analysis, formatting, and diff checks are green. The final tree has been reviewed and signed off.

@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown

Tip

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

@binaryfire The follow-up addresses the raw-block finding.

compileString() now isolates raw-block state per compile pass. The finally cleanup also bounds component-hash state after both successful and failed compilation.

Keeping component hashes available at pass entry preserves the newComponentHash() seed-then-compile contract. The clarified stringable() documentation also matches the supported API.

The malformed-nesting test is not required. Compilation produces PHP, and PHP execution remains the correct failure boundary.

🐇 ✅


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

Timestamp: 2026-08-06T14:41:53.298Z
Learning: In `src/view/src/Compilers/BladeCompiler.php`, `BladeCompiler::compileString()` must preserve component-hash frames at compile-pass entry because the public `newComponentHash()` API can seed the immediately following pass. It must clear component-hash frames when the pass exits, including when compilation throws, to bound worker-lived state without breaking the Laravel-compatible sequence.

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.

You are interacting with an AI system.

@binaryfire

Copy link
Copy Markdown
Collaborator Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@binaryfire
binaryfire merged commit 51709b4 into 0.4 Aug 6, 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