Skip to content

Improve parallel testing and Testbench package mode#416

Merged
binaryfire merged 20 commits into
0.4from
feature/parallel-redis-testbench-isolation
Jul 6, 2026
Merged

Improve parallel testing and Testbench package mode#416
binaryfire merged 20 commits into
0.4from
feature/parallel-redis-testbench-isolation

Conversation

@binaryfire

@binaryfire binaryfire commented Jul 6, 2026

Copy link
Copy Markdown
Collaborator

Summary

This PR makes Hypervel's parallel testing and Testbench package mode behave like first-class paths instead of repo-specific special cases.

The full components suite now runs through raw ParaTest, with the parallel-testing flag supplied by PHPUnit config. Testbench package behavior is covered separately through a scoped package:test suite. This keeps framework tests out of package-tester semantics while still testing the real Testbench command path.

Redis test isolation now happens at runtime, only when a test opts into the Redis testing helper. Each parallel worker gets a configured logical database, secondary Redis database usage is explicit, and the old components-only Redis preflight wrapper is gone.

Testbench package mode now has tighter env ownership. Package-test children receive command-owned variables and declared Testbench YAML env values, not the parent CLI application's whole loaded runtime env. The runtime skeleton still loads package/workbench env files through the normal Testbench path, so package authors get the expected behavior without parent-process leakage.

This also fixes the issues that fell out of exercising Testbench as a real package runner: route cache paths before setup, route file ownership, runtime clone cleanup races, AOP proxy source-map drift, package manifest discovery in workers, and a leaked app base path channel.

Finally, this adds a real dogfood package outside the components root. It installs Testbench through Composer, runs vendor/bin/testbench package:test --parallel, proves provider discovery and workbench loading, and runs in CI.

For more details, see: docs/plans/2026-07-05-parallel-redis-runtime-isolation.md and docs/plans/2026-07-06-testbench-package-mode-dogfood.md.

What changed

  • Removed the components-only bin/paratest wrapper.
  • Split the test gates into raw framework ParaTest and scoped Testbench package-mode tests.
  • Added runtime Redis database allocation for parallel tests.
  • Added explicit REDIS_TEST_DB_MIN, REDIS_TEST_DB_MAX, and REDIS_TEST_SECONDARY_DB behavior.
  • Fixed Testbench env cleanup and stopped forwarding arbitrary parent CLI env into package-test workers.
  • Added shared Testbench env-file resolution for package/workbench env files and skeleton fallback behavior.
  • Updated the Testbench skeleton package-mode env defaults so upstream mode-keyed expectations hold under package:test.
  • Added TESTBENCH_CORE to the Testbench binary so CLI package behavior matches Orchestra's.
  • Fixed Testbench route cache and route-file handling for parallel package-mode runs.
  • Fixed runtime skeleton cleanup races for concurrent Testbench children.
  • Fixed AOP proxy generation so generated proxy paths do not poison later source-map reads.
  • Removed the leaked TESTBENCH_APP_BASE_PATH runtime channel.
  • Added deterministic root package metadata discovery inside package-test workers.
  • Stopped the components root provider aggregate from being auto-discovered during Testbench's own package-mode suite.
  • Added serve --host and serve --port support at the shared server command layer.
  • Added root Composer binary metadata for Testbench and facade-documenter.
  • Moved the committed Testbench workbench fixtures to dev autoload so they no longer leak into consumer autoloaders.
  • Added the dogfood/testbench-package fixture and CI coverage.
  • Updated Boost docs, Testbench README notes, CI, and agent guidance for the new testing shape.

Why

The old setup worked, but too much of it was accidental. A parent wrapper connected to Redis before the suite started, Testbench package mode was not exercised like a package would use it, and some parent CLI env values could leak into child workers.

The new shape puts each behavior where it belongs:

  • Redis setup lives with Redis tests.
  • Framework tests run as framework tests.
  • Package-mode tests run through Testbench.
  • Package env files are loaded by the package runtime, not smuggled through the parent command.
  • Third-party package behavior is proved by an actual package.

Testing

Ran the focused Redis, Testbench, server command, route-cache, package manifest, dogfood, and package-mode suites while building this.

Ran composer fix, which covers code style, PHPStan, raw ParaTest, the scoped Testbench package-mode suite, and the dogfood package suite.

Summary by CodeRabbit

  • New Features
    • Added serve command --host / --port options for overriding the HTTP address.
    • Introduced new test workflows for Testbench package-mode and dogfood coverage (test:testbench, test:dogfood), with improved parallel execution behavior.
  • Bug Fixes
    • Strengthened parallel test Redis isolation with deterministic per-worker DB selection and optional secondary DB support.
    • Improved test environment cleanup, runtime env-file copying, and safer generated route cleanup.
  • Documentation
    • Updated Boost/Testbench docs to reflect Redis parallel behavior and the new serve options.
  • Tests
    • Expanded CI and test coverage around proxy regeneration, Redis isolation, and Testbench runtime behavior.

binaryfire added 19 commits July 5, 2026 13:59
Cast ParaTest process tokens to strings when resolving the Hypervel parallel testing token from ParallelRunner. ParallelTesting::token() is typed as string|false, while Collection::range() yields integers, so the resolver should preserve the public token contract.

Add focused coverage proving process tokens are exposed as string values during ParallelRunner iteration.

Also correct the InteractsWithRedis testing docblock so the documented REDIS_DB default matches the actual framework config and helper behavior: 0, not 1.
Document the agreed design for replacing the components Redis preflight wrapper with runtime Redis isolation owned by the testing helpers.

The plan captures the final split between raw framework ParaTest runs and scoped Testbench package-mode contract runs, including why package:test should not be the full mixed-suite runner for the components repository.

It also records the Testbench environment ownership decisions, Redis worker database allocation rules, secondary database behavior, route cache isolation work, AOP source-map fix, documentation updates, and the focused/full test plan used to verify the change.
Move Redis worker database selection out of the components preflight wrapper and into the testing runtime that actually uses Redis.

Introduce RedisTestDatabases as the shared allocator for InteractsWithRedis and subprocess bootstraps such as the Horizon worker fixture. Parallel workers now use REDIS_TEST_DB_MIN through REDIS_TEST_DB_MAX, skip an explicitly configured REDIS_TEST_SECONDARY_DB, and fail clearly when the configured range cannot cover the active worker token.

Sequential Redis tests continue to use REDIS_DB directly. Secondary database use is now explicit through REDIS_TEST_SECONDARY_DB so normal app and package tests do not reserve or touch a second Redis database unless a test asks for one.

Update Redis integration cleanup so shared secondary database tests delete their own keys, and configure the Redis workflow and example env file with the secondary database needed by the low-level Redis integration suite.
Fix TestCommandBase::clearEnv() so test commands remove parent application dotenv values from every environment store before spawning PHPUnit or ParaTest.

The previous implementation called the immutable repository writer's clear() method after enablePutenv() rebuilt the repository. That writer had not loaded the parent dotenv keys, so it treated them as external values and refused to clear them, allowing values to leak into Symfony child processes.

Use Env::deleteMany() after rebuilding the adapter list so keys from the configured dotenv file are removed from \, \, and the putenv adapter. Add coverage proving the command clears all three stores.
Stop forwarding the parent Testbench CLI application's full runtime environment to package test child processes.

Add EnvironmentFile as the shared resolver for package and workbench env files, and use it from both the skeleton sync command path and Bootstrapper runtime clone creation. In package-test mode the resolved package/workbench env file, or the skeleton fallback, is copied into the child runtime application as .env; outside package-test mode Bootstrapper leaves raw PHPUnit Testbench behavior alone.

Keep explicit Testbench YAML env values as the command-owned package-test channel and preserve package command variables as the final overrides. Add coverage for not forwarding parent runtime env, forwarding configured YAML env, package command override precedence, runtime clone env copying, skeleton fallback copying, and raw-mode non-copying.

Also make runtime clone deletion tolerant of same-token sibling cleanup races by retrying once and accepting the desired postcondition only when the directory is actually gone.
Make cached route setup safe for Testbench package-mode parallel runs.

Configure worker-specific route cache paths before application setup when defineCacheRoutes() is called early, because those tests can run before the application and ParallelTesting service exist.

Write unique route fixture files per test instance using the worker token, process id, and monotonic time, then delete only the files owned by that test. This preserves remote child route synchronization while preventing one test from deleting sibling route files that another test still needs.

Normalize glob() results before route sync and harden the serve smoke test diagnostics and port selection so package-mode parallel failures point at the real issue.
Restore Testbench package-mode defaults that package tests expect from the skeleton environment.

Add SESSION_DRIVER=cookie and CACHE_STORE=database to the skeleton .env.example so package-test mode exercises the same defaults as the upstream Testbench contract. Keep the session config minimal by reading the driver from env while leaving framework base config merge to provide the rest of the session configuration.

Add the missing return types in the related env tests while touching the Testbench env contract area.
Keep Testbench's own package-mode contract suite from auto-discovering the hypervel/components root package aggregate.

The components root package is a monorepo development aggregate, not the package-under-test for Testbench's contract tests. Ignoring it in Testbench's own testbench.yaml prevents optional providers such as Fortify from leaking into Slim skeleton package-mode tests while preserving normal discovery behavior for real packages.

Add coverage that package-specific dont-discover entries filter the manifest view even when the cached package file still contains the root package metadata. Record the remaining package-author discovery determinism cleanup in docs/todo.md so the broader runtime clone seeding behavior is handled deliberately later.
Fix AOP proxy regeneration when Composer's runtime class map already contains generated proxy paths.

GenerateProxies now maintains a source class map, filters generated .proxy.php entries out of harvested Composer maps, and rejects exact findFile() results that point back to generated proxies. Ast can receive the known source file path directly, avoiding a second lookup through a loader that may already have proxy paths installed.

ProxyManager now records the source file used for each generated proxy so source-path drift from later class-map overrides forces regeneration even when mtimes would otherwise hide the change.

Add coverage for deleted proxy regeneration, PSR-4 proxy path rejection after source map flushes, newer source regeneration, source-path changes, and loader restoration for controlled test fixtures.
Extract the repeated purge/sync skeleton command test preservation logic into a shared PreservesSkeletonFiles trait.

Both command tests now snapshot the exact skeleton files they mutate, restore existing files with their parent directories, and delete files that did not exist before the test. This keeps the shared Testbench runtime skeleton stable across package-mode tests without duplicating file, directory, and symlink cleanup logic in each test class.
Define TESTBENCH_CORE in the Testbench binary after loading Composer's autoloader.

This matches Orchestra's binary shape and makes is_testbench_cli() true for real Testbench CLI executions. Package commands are visible through the Testbench CLI and package manifest discovery can include the package-under-test metadata through the intended command path.
Replace the components-specific bin/paratest wrapper with raw ParaTest for the full framework suite.

The Redis preflight wrapper no longer owns Redis setup; runtime Redis isolation now happens inside the testing helpers that actually touch Redis. phpunit.xml.dist supplies HYPERVEL_PARALLEL_TESTING so raw vendor/bin/paratest and composer test:parallel use the same framework parallel-testing setup.

Add composer test:testbench for the scoped Testbench package-mode contract suite and wire it into composer check and composer fix so framework tests and package-mode behavior are both covered by the standard local gates.
Split the main tests workflow into clearer style, framework suite, and Testbench package-mode steps.

Keep the framework suite on sequential PHPUnit so CI avoids ParaTest scheduling noise, while adding the scoped package:test --parallel tests/Testbench run that verifies the package-mode contract introduced by the new local gates.
Update maintainer and user-facing docs for the new test infrastructure split.

AGENTS.md now points maintainers at composer test:parallel for the raw components framework suite and composer test:testbench for the scoped Testbench package-mode contract suite, including the Redis worker range caveat for ParaTest process counts.

The Boost testing docs now describe Redis database allocation for tests using InteractsWithRedis, including REDIS_TEST_DB_MIN, REDIS_TEST_DB_MAX, REDIS_TEST_SECONDARY_DB, worker overflow behavior, and string token callback signatures.

The Testbench docs and README document package-test parallel behavior and the intentional difference from Orchestra: Hypervel does not forward the parent Testbench CLI application's full runtime environment to child test processes; package/workbench env files are loaded through the runtime app clone instead.
Remove the Testbench-specific TESTBENCH_APP_BASE_PATH channel so package-test worker processes cannot inherit the parent CLI application's runtime clone identity.

Package tests now keep the path ownership model explicit: BASE_PATH identifies the current process runtime clone, TESTBENCH_BASE_PATH is reserved for remote child handoff, and APP_BASE_PATH remains the user override. This removes the old Orchestra-style per-class env pointer and its lifecycle hooks because Hypervel's Testbench clones the selected skeleton as the process identity instead of switching source skeleton paths through shared env state.

Update the package test command and parallel runner to stop emitting or hydrating TESTBENCH_APP_BASE_PATH. Update Workbench path resolution to honor only APP_BASE_PATH, delete the now-empty setup and teardown hooks, and document the deliberate Orchestra difference in the Testbench README and implementation plan.

Add regression coverage proving package test command environments omit TESTBENCH_APP_BASE_PATH and stray values are ignored while APP_BASE_PATH still works as the explicit override.
Package-test workers are not Testbench CLI processes, but they still need the package root metadata that Testbench uses to build deterministic package manifests. Include root metadata when TESTBENCH_PACKAGE_TESTER is present so the first manifest builder in a worker sees the same providers as child Testbench commands.\n\nAdd subprocess coverage for package-tester workers, plain non-Testbench processes, and Testbench CLI processes. Each scenario writes to its own generated manifest file so CLI opcache cannot reuse a stale required path across cases.
Add --host and --port options to the shared server start command and apply them before the Swoole server configuration is built. Testbench's serve command now inherits the same behavior instead of relying on callers to seed HTTP_SERVER_HOST or HTTP_SERVER_PORT in the environment.\n\nValidate non-integer ports, reject address overrides when no HTTP server is configured, and cover the multi-server case by proving the override is applied to the HTTP server by type rather than by array position.
Add a minimal external package that consumes the local Testbench binary through Composer bin discovery and runs package:test --parallel from its own project root. The dogfood suite proves provider discovery, workbench provider loading, package configuration, remote CLI calls, and package-mode parallel execution outside the components repository.\n\nWire the dogfood suite into Composer and CI, ignore only its generated vendor, lock, and PHPUnit cache artifacts, and exclude its vendor directory from CS Fixer. Move Workbench namespace mappings in the root and split Testbench Composer manifests to autoload-dev so consumers are not polluted by test-only Workbench classes while local development and Testbench tests continue to autoload them.
Record the package-mode follow-up plan, its reviewed decisions, and the testing strategy used for the Testbench dogfood work. Remove the completed Testbench todo now that deterministic package-worker metadata discovery is implemented and covered.\n\nDocument the package-test manifest behavior and the new serve --host/--port flags in the Testbench README and Boost docs, keeping the wording aligned with the surrounding documentation and noting production should prefer durable server configuration.
@coderabbitai

coderabbitai Bot commented Jul 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: 26883dd8-beed-4ac2-982f-35e5b4a5725c

📥 Commits

Reviewing files that changed from the base of the PR and between 65c40d7 and 3df81e9.

📒 Files selected for processing (8)
  • src/server/src/Commands/ServerStartCommand.php
  • src/testbench/src/Concerns/CreatesApplication.php
  • src/testbench/src/Concerns/HandlesRoutes.php
  • src/testing/src/Concerns/RunsInParallel.php
  • tests/Server/ServerStartCommandTest.php
  • tests/Testbench/BootstrapperTest.php
  • tests/Testbench/Concerns/CreatesApplicationTest.php
  • tests/Testing/ParallelRunnerTest.php
🚧 Files skipped from review as they are similar to previous changes (4)
  • src/testbench/src/Concerns/CreatesApplication.php
  • src/server/src/Commands/ServerStartCommand.php
  • src/testbench/src/Concerns/HandlesRoutes.php
  • tests/Testbench/BootstrapperTest.php

📝 Walkthrough

Walkthrough

This PR replaces the custom parallel test wrapper, centralizes Redis worker database selection, refactors Testbench runtime/env handling, adds serve --host/--port, updates AOP proxy source tracking, and introduces a dogfood Testbench package with matching tests and docs.

Changes

Parallel Redis isolation and test execution wiring

Layer / File(s) Summary
Planning documents
docs/plans/2026-07-05-...md, docs/plans/2026-07-06-...md
Adds planning documents for the Redis isolation, Testbench package mode, and dogfood package work.
Wrapper removal & CI/build config
bin/paratest, composer.json, phpunit.xml.dist, .github/workflows/*.yml, .gitignore, .php-cs-fixer.php, .env.example, AGENTS.md
Deletes the wrapper, switches test:parallel to raw paratest, adds new scripts and CI steps, sets Redis test env defaults, and updates ignore/exclude rules.
RedisTestDatabases allocation
src/foundation/src/Testing/RedisTestDatabases.php
Adds deterministic Redis DB selection helpers for base, worker, primary, and secondary databases.
InteractsWithRedis & Horizon worker refactor
src/foundation/.../InteractsWithRedis.php, src/testing/src/Concerns/RunsInParallel.php, tests/Integration/Horizon/worker.php
Routes Redis DB selection through the shared helper and aligns worker token handling with string tokens.
Redis test coverage & integration cleanup
tests/Foundation/.../InteractsWithRedisParallelTest.php, tests/Testing/ParallelRunnerTest.php, tests/Integration/Redis/RedisProxyIntegrationTest.php
Rewrites Redis-related tests around explicit env mutation, token resolvers, and cleanup guards.
Boost Redis docs
src/boost/docs/testing.md
Documents the parallel Redis DB selection model and string token examples.

Testbench env ownership and runtime clone refactor

Layer / File(s) Summary
EnvironmentFile helper
src/testbench/src/Foundation/EnvironmentFile.php, .../CopyTestbenchFiles.php
Adds env/source resolution with skeleton fallback and rewires copy logic to use it.
Bootstrapper runtime copy/deletion
src/testbench/src/Bootstrapper.php, src/testbench/bin/testbench
Threads working-path runtime copy creation, copies package env files conditionally, adds race-tolerant deletion, and defines TESTBENCH_CORE.
TestCommand/TestCommandBase env handling
.../Foundation/Console/TestCommand.php, src/testing/src/Console/TestCommandBase.php, src/testbench/src/Foundation/PackageManifest.php
Parses config env, removes TESTBENCH_APP_BASE_PATH, bulk-deletes dotenv keys, and broadens package-manifest gating.
Remove TESTBENCH_APP_BASE_PATH channel
InteractsWithWorkbench.php, ParallelRunner.php, TestCase.php, tests
Removes the legacy env channel from runtime and test lifecycle wiring.
Route cache paths & autoload split
CreatesApplication.php, HandlesRoutes.php, SyncTestbenchCachedRoutes.php, composer.json files, session/env config
Derives sanitized worker route cache paths, tracks owned route files, and moves Workbench autoload entries to autoload-dev.
Bootstrapper & env tests
tests/Testbench/BootstrapperTest.php, PreservesSkeletonFiles.php, various test files
Adds runtime-copy/deletion tests, shared skeleton-file preservation, and env-forwarding coverage.
PackageManifest gating & tests
PackageManifest.php, testbench.yaml, fixtures
Adds TESTBENCH_PACKAGE_TESTER gating plus subprocess-backed manifest tests.
README docs
src/testbench/README.md
Documents differences from Orchestra Testbench.

Server serve --host/--port options

Layer / File(s) Summary
ServerStartCommand implementation
src/server/src/Commands/ServerStartCommand.php, ServeCommand.php
Adds CLI options and applies validated host/port overrides to the configured HTTP server before startup.
Tests
ServerStartCommandTest.php, CommanderServeTest.php
Updates server-start and serve-process tests for structured config and CLI option behavior.
Docs
src/boost/docs/*.md
Documents the new host/port override options.

AOP proxy source-path tracking fix

Layer / File(s) Summary
Ast/ProxyManager tracking
Ast.php, ProxyManager.php
Tracks source file paths per proxy and invalidates stale proxies when the source path changes.
GenerateProxies cache
GenerateProxies.php
Caches Composer-resolved source class maps across generation runs with flush support.
Tests
tests/Di/Bootstrap/GenerateProxiesTest.php
Adds fixture-based regression coverage for proxy regeneration scenarios.

Dogfood Testbench package fixture

Layer / File(s) Summary
Package fixture
dogfood/testbench-package/*
Adds a standalone package with providers, probe command, workbench config, and runtime tests for package mode.

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

Possibly related PRs

  • hypervel/components#403: Related through shared changes to TestCommandBase::clearEnv() bulk env-clearing logic in src/testing/src/Console/TestCommandBase.php.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main changes: parallel testing improvements and Testbench package-mode updates.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/parallel-redis-testbench-isolation

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

Copy link
Copy Markdown

Greptile Summary

This PR restructures parallel testing and Testbench package-mode to make each concern first-class rather than bolt-on. Framework tests now run through raw ParaTest (no custom wrapper), Testbench package-mode tests run through the real package:test command, and Redis database allocation moves from a parent-process preflight to a per-test runtime allocation.

Key changes:

  • Redis isolation: New RedisTestDatabases class computes per-worker database slots from REDIS_TEST_DB_MIN/REDIS_TEST_DB_MAX; secondary DB must now be declared via REDIS_TEST_SECONDARY_DB — previously it was computed silently, now it throws if unset.
  • Testbench env scope: Package-test child workers no longer inherit the parent CLI's full environment; only YAML env: keys and explicitly owned vars are forwarded. Bootstrapper now copies the package/workbench env file into the runtime skeleton during clone.
  • Bug fixes: Route file ownership per-instance instead of glob-all, proxy source-path drift detection via static $generatedFrom map, concurrent skeleton cleanup race tolerance, and deterministic package manifest discovery inside workers.

Confidence Score: 5/5

Safe to merge. All behavioral changes are intentional and well-documented; the redis.yml and tests.yml workflows are correctly updated to match the new env var contract.

The changes make parallel testing and Testbench package mode first-class. Redis DB allocation, env scope, route file ownership, proxy source-path tracking, and skeleton cleanup races are all addressed with explicit contracts and tests. No silent regressions were found; the only API-surface change (getSecondaryRedisDb now requires REDIS_TEST_SECONDARY_DB) is reflected correctly in all callers and CI workflows.

No files require special attention. src/testbench/src/Foundation/Console/TestCommand.php uses phpdotenv internal classes (flagged in a prior thread) but the logic itself is functionally correct.

Important Files Changed

Filename Overview
src/foundation/src/Testing/RedisTestDatabases.php New class centralising parallel Redis DB allocation; well-validated with explicit range checks and a clear worker-index-to-database mapping. Overflow now throws RuntimeException (was a skip).
src/foundation/src/Testing/Concerns/InteractsWithRedis.php Delegates all DB calculations to RedisTestDatabases; removes the static overflow flag and the pre-suite Redis connection check. Existing callers of getSecondaryRedisDb() must now set REDIS_TEST_SECONDARY_DB — updated correctly in redis.yml.
src/testbench/src/Foundation/Console/TestCommand.php Replaces defined_environment_variables() (all parent env) with YAML-declared env only; drops TESTBENCH_APP_BASE_PATH from worker env. Uses phpdotenv internal Parser/StringStore (flagged in a prior thread) to parse the YAML env array.
src/testbench/src/Foundation/EnvironmentFile.php New resolver extracting env-file lookup logic shared between CopyTestbenchFiles and Bootstrapper; candidate ordering and skeleton fallback are identical to the previous inline code.
src/testbench/src/Bootstrapper.php Runtime-copy creation now takes workingPath for env file injection; stale-copy cleanup uses double-retry with clearstatcache to tolerate concurrent sibling bootstraps; signature changes are consistent throughout.
src/di/src/Aop/ProxyManager.php Adds static $generatedFrom map so isModified() detects when a proxy was previously generated from a different source path, forcing regeneration. flushState() is test-only and well-documented.
src/di/src/Bootstrap/GenerateProxies.php Static $sourceClassMap accumulates non-proxy paths across boots; proxy files are excluded from both mergeSourceClassMap() and the PSR-4 findFile() fallback, preventing a flushed map from re-registering proxy entries as sources.
src/testbench/src/Concerns/HandlesRoutes.php Route files are now named per-worker/per-pid/hrtime so parallel test instances cannot collide; cleanup tracks only files owned by the current test instance rather than a glob, fixing parallel-safe teardown.
src/testing/src/Concerns/RunsInParallel.php Token cast to string (was int) so ParallelTesting::token() type matches the rest of the stack; resolveTokenUsing(null) moved to finally so the resolver is always cleared even if the callback throws.
src/testing/src/Console/TestCommandBase.php clearEnv() now calls Env::getRepository() to ensure $adapters is populated before Env::deleteMany(), bypassing the ImmutableWriter that refused to clear keys it didn't load.
src/server/src/Commands/ServerStartCommand.php Adds --host and --port options; port validated with FILTER_VALIDATE_INT and min_range=1/max_range=65535; both config and the config repository are updated so workers see the correct bound address.
dogfood/testbench-package/composer.json New dogfood package that runs package:test --parallel against a real Composer-installed Testbench; uses path repository with symlink to the components root, composer.lock gitignored.
src/testbench/src/Concerns/InteractsWithWorkbench.php Drops TESTBENCH_APP_BASE_PATH from applicationBasePathUsingWorkbench() and removes setUpBeforeClassUsingWorkbench/tearDownAfterClassUsingWorkbench; per-class skeleton switching is incompatible with process-owned runtime clones.

Reviews (2): Last reviewed commit: "fix(testing): address package-mode revie..." | Re-trigger Greptile

Comment thread src/server/src/Commands/ServerStartCommand.php Outdated
Comment thread src/testbench/src/Foundation/Console/TestCommand.php

Copilot AI 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.

Pull request overview

This PR reworks Hypervel’s parallel testing and Testbench “package mode” to behave like first-class, tool-native flows (raw ParaTest + real testbench package:test), while moving Redis isolation and package-mode env handling into runtime-owned, worker-safe paths. It also adds a standalone “dogfood” package to validate real consumer behavior outside the monorepo root.

Changes:

  • Switch the components parallel test path to raw ParaTest and add a scoped test:testbench suite that exercises real package-mode execution.
  • Move Redis parallel isolation to runtime allocation (worker DB ranges + explicit secondary DB) and update integration/tests/docs accordingly.
  • Harden Testbench package-mode behavior (env ownership, runtime clone cleanup races, deterministic package manifest discovery, serve host/port overrides) and add a dogfood package + CI coverage.

Reviewed changes

Copilot reviewed 66 out of 69 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
tests/Testing/ParallelRunnerTest.php Adds regression coverage for string process tokens and ParaTest Options wiring.
tests/Testing/Console/TestCommandTest.php Adds coverage for clearing env vars across all env stores.
tests/Testbench/WithWorkbenchTest.php Updates workbench config expectations; verifies ignoring stray base-path env.
tests/Testbench/Foundation/PackageManifestTest.php Adds coverage for filtering by specific package names.
tests/Testbench/Foundation/PackageManifestPackageTesterTest.php New subprocess-backed tests for deterministic root metadata discovery gating.
tests/Testbench/Foundation/Fixtures/PackageManifest/build-manifest.php New helper script to build a manifest in a fresh PHP process.
tests/Testbench/Foundation/EnvTest.php Adds missing : void return types to tests.
tests/Testbench/Foundation/Console/TestCommandTest.php Expands package-test env forwarding/ownership assertions.
tests/Testbench/Foundation/Console/SyncSkeletonCommandTest.php Preserves/restores skeleton files to avoid cross-test contamination.
tests/Testbench/Foundation/Console/PurgeSkeletonCommandTest.php Preserves/restores skeleton files for purge command tests.
tests/Testbench/Concerns/PreservesSkeletonFiles.php New test helper trait to snapshot/restore skeleton files.
tests/Testbench/Concerns/DefineCacheRoutesTest.php Adds coverage for owned route-file tracking and cleanup behavior.
tests/Testbench/CommanderServeTest.php Updates serve smoke test to use --host/--port options and improves port selection.
tests/Testbench/BootstrapperTest.php Adds coverage for runtime clone deletion races and env-file copy behavior.
tests/Server/ServerStartCommandTest.php Updates server config shape and adds host/port override validation tests.
tests/Integration/Redis/RedisProxyIntegrationTest.php Improves cleanup/isolation around select() and pipeline concurrency.
tests/Integration/Horizon/worker.php Uses new Redis DB allocator for subprocess worker isolation.
tests/Foundation/Testing/Concerns/InteractsWithRedisParallelTest.php Replaces older Redis token math tests with range-based allocation tests.
tests/Di/Bootstrap/GenerateProxiesTest.php Adds coverage for proxy source-map drift and regeneration behavior; flushes new state.
src/testing/src/Console/TestCommandBase.php Changes env cleanup implementation to delete keys across adapters.
src/testing/src/Concerns/RunsInParallel.php Ensures parallel process tokens are resolved as strings.
src/testbench/testbench.yaml Adds dont-discover to avoid auto-discovering hypervel/components in package mode.
src/testbench/src/TestCase.php Removes workbench per-class base-path env setup/teardown hooks.
src/testbench/src/Foundation/PackageManifest.php Adds package-tester gate to include root metadata in package-test workers.
src/testbench/src/Foundation/EnvironmentFile.php New resolver for package/workbench env files with skeleton fallback.
src/testbench/src/Foundation/Console/TestCommand.php Stops forwarding full parent env; forwards only declared Testbench YAML env + command vars.
src/testbench/src/Foundation/Console/ServeCommand.php Passes input into the shared server start path.
src/testbench/src/Foundation/Console/Concerns/CopyTestbenchFiles.php Switches env/config source resolution to the new EnvironmentFile helper.
src/testbench/src/Foundation/Bootstrap/SyncTestbenchCachedRoutes.php Avoids glob() false handling by normalizing to an empty array.
src/testbench/src/Features/ParallelRunner.php Removes TESTBENCH_APP_BASE_PATH injection into env.
src/testbench/src/Concerns/InteractsWithWorkbench.php Removes reliance on TESTBENCH_APP_BASE_PATH; documents intentional divergence.
src/testbench/src/Concerns/HandlesRoutes.php Ensures per-instance route-file ownership tracking + unique route file paths.
src/testbench/src/Concerns/CreatesApplication.php Reads ParaTest token from raw superglobals when app/ParallelTesting aren’t available yet.
src/testbench/src/Bootstrapper.php Improves runtime clone ownership, env-file copying in package mode, and deletion race tolerance.
src/testbench/README.md Documents intentional divergences from Orchestra Testbench.
src/testbench/hypervel/config/session.php Adjusts skeleton session config to respect SESSION_DRIVER env.
src/testbench/hypervel/.env.example Updates skeleton defaults (session/cache related).
src/testbench/composer.json Moves Workbench autoloading to autoload-dev.
src/testbench/bin/testbench Defines TESTBENCH_CORE to align CLI behavior with Orchestra expectations.
src/server/src/Commands/ServerStartCommand.php Adds --host/--port options and applies overrides to configured HTTP server before start.
src/foundation/src/Testing/RedisTestDatabases.php New centralized allocator for Redis DB selection/ranges/secondary DB logic.
src/foundation/src/Testing/Concerns/InteractsWithRedis.php Switches parallel Redis isolation to range-based allocator and removes preflight wrapper logic.
src/di/src/Bootstrap/GenerateProxies.php Captures/merges a stable source class map and adds test-only flush hook.
src/di/src/Aop/ProxyManager.php Tracks source path used for existing proxies and supports test-only flush.
src/di/src/Aop/Ast.php Allows passing explicit source path for proxy generation.
src/boost/docs/testing.md Documents parallel Redis DB range behavior; updates token type examples.
src/boost/docs/testbench.md Documents serve --host/--port and notes package tests inherit parallel isolation behavior.
src/boost/docs/lifecycle.md Notes serve host/port options apply before workers start.
src/boost/docs/installation.md Documents serve host/port overrides.
src/boost/docs/deployment.md Mentions serve host/port overrides and production guidance.
phpunit.xml.dist Sets HYPERVEL_PARALLEL_TESTING=1 via config to enable parallel mode detection in ParaTest runs.
dogfood/testbench-package/workbench/config/dogfood.php New dogfood workbench config fixture.
dogfood/testbench-package/workbench/app/Providers/WorkbenchServiceProvider.php New dogfood workbench provider fixture.
dogfood/testbench-package/tests/PackageRuntimeTest.php Dogfood tests proving provider discovery, workbench loading, remote commands, and parallel package mode.
dogfood/testbench-package/testbench.yaml Dogfood Testbench config enabling workbench install/config discovery.
dogfood/testbench-package/src/DogfoodServiceProvider.php Dogfood package provider and command registration.
dogfood/testbench-package/src/DogfoodProbeCommand.php Dogfood command used to verify remote command execution in package runtime.
dogfood/testbench-package/phpunit.xml.dist Dogfood PHPUnit config using AfterEachTestExtension.
dogfood/testbench-package/composer.json Dogfood package metadata and scripts to run testbench package:test --parallel.
docs/plans/2026-07-06-testbench-package-mode-dogfood.md Detailed plan/spec describing the new package-mode + dogfood + serve options behavior.
composer.json Adds root bin metadata, new test scripts (test:testbench, test:dogfood), and switches parallel script to raw paratest.
bin/paratest Removes the components-only ParaTest wrapper.
AGENTS.md Updates agent guidance for new testing commands and Redis DB range requirements.
.php-cs-fixer.php Excludes dogfood vendor directory from fixer traversal.
.gitignore Ignores dogfood vendor/lock/cache artifacts.
.github/workflows/tests.yml Splits CI into style + framework + Testbench package-mode + dogfood runs.
.github/workflows/redis.yml Adjusts Redis env defaults for the new isolation scheme.
.env.example Adds Redis parallel test DB range variables.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@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/testing/src/Concerns/RunsInParallel.php (1)

111-119: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Reset the token resolver after each worker callback.

resolveTokenUsing() writes static state, but this loop never clears it. The last worker token can leak into later callbacks or any code that calls ParallelTesting::token() after the loop finishes.

Suggested fix
-        tap($this->createApplication(), function ($app) use ($callback, $token) {
-            ParallelTesting::resolveTokenUsing(fn () => (string) $token);
-
-            $callback($app);
-        })->flush();
+        $app = $this->createApplication();
+
+        try {
+            ParallelTesting::resolveTokenUsing(fn () => (string) $token);
+            $callback($app);
+            $app->flush();
+        } finally {
+            ParallelTesting::resolveTokenUsing(null);
+        }
🤖 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/testing/src/Concerns/RunsInParallel.php` around lines 111 - 119, The
`forEachProcess` loop in `RunsInParallel` leaves
`ParallelTesting::resolveTokenUsing()` set after each worker callback, so the
last token can leak into later work. Update the `forEachProcess` flow to restore
or clear the token resolver immediately after `$callback($app)` finishes for
each token. Keep the change localized around
`ParallelTesting::resolveTokenUsing` and the `tap(...)->flush()` sequence so
`ParallelTesting::token()` does not retain stale state after the loop.
🧹 Nitpick comments (3)
src/testbench/README.md (1)

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

Heading name diverges from guideline wording.

As per coding guidelines, ported packages should note intentional differences under a heading Differences From Laravel; this uses Differences From Orchestra Testbench instead. Since Testbench's direct upstream is Orchestra (not Laravel core), this may be an intentional/acceptable exception, but flagging for consistency with the stated convention.

🤖 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/testbench/README.md` at line 8, The README heading in the Testbench
package does not match the documented convention for ported packages. Update the
markdown heading from the current Orchestra-specific wording to the standard
“Differences From Laravel” phrasing, or if this is intended as an exception,
align the surrounding copy in the README to clearly follow the project’s
convention consistently.

Source: Coding guidelines

src/testbench/src/Concerns/CreatesApplication.php (1)

574-597: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Sanitize TEST_TOKEN before using it in APP_ROUTES_CACHE, for consistency with HandlesRoutes.

paraTestWorkerToken() only checks the token is a non-empty string, then interpolates it directly into a filesystem path (cache/routes-v7-test-{$token}.php). The sibling implementation in HandlesRoutes::testbenchRouteFilePath() reads the same TEST_TOKEN source but strips unsafe characters via preg_replace('/[^A-Za-z0-9_.-]/', '_', $token) before building a path. Since TEST_TOKEN is normally a numeric ParaTest worker id, this is low risk today, but the two call sites disagree on whether the token is trusted for path construction, and this path could later be consumed by join_paths(...) in HandlesRoutes without validation.

🛡️ Proposed fix to align token sanitization
     protected function paraTestWorkerToken(): ?string
     {
         $token = $_SERVER['TEST_TOKEN'] ?? $_ENV['TEST_TOKEN'] ?? null;

-        return is_string($token) && $token !== '' ? $token : null;
+        if (! is_string($token) || $token === '') {
+            return null;
+        }
+
+        return preg_replace('/[^A-Za-z0-9_.-]/', '_', $token) ?? null;
     }
🤖 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/testbench/src/Concerns/CreatesApplication.php` around lines 574 - 597,
The APP_ROUTES_CACHE path in configureParallelCachePaths uses
paraTestWorkerToken() without sanitizing the TEST_TOKEN value, which is
inconsistent with HandlesRoutes::testbenchRouteFilePath(). Update
paraTestWorkerToken() or the cache path construction to normalize the token the
same way as HandlesRoutes does (replace unsafe characters before interpolation)
so the token is safe for filesystem paths and both implementations stay aligned.
tests/Testbench/BootstrapperTest.php (1)

66-173: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Extract shared env/package-tester setup+restore boilerplate.

The correctness of these three tests checks out against Bootstrapper::createRuntimeCopy/copyPackageEnvironmentFile (workbench-preference, skeleton fallback, and package-tester-off skip paths all match). However, each test repeats ~30 lines of near-identical $_SERVER/$_ENV/getenv capture-and-restore logic for TEST_TOKEN and TESTBENCH_PACKAGE_TESTER. Consider wrapping this in a single helper (e.g. withRuntimeCopyEnvironment(string $token, bool $packageTester, callable $assertions)) that handles setup/teardown internally, reducing ~90 lines of duplication to one reusable method.

🤖 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 `@tests/Testbench/BootstrapperTest.php` around lines 66 - 173, The three
BootstrapperTest cases repeat the same TEST_TOKEN and TESTBENCH_PACKAGE_TESTER
capture/setup/restore boilerplate, even though the assertions already cover the
intended createRuntimeCopy and copyPackageEnvironmentFile behavior. Extract that
repeated environment handling into one reusable helper in BootstrapperTest (for
example, a wrapper that saves/restores $_SERVER, $_ENV, and getenv state while
running a callback) and have it manage the temporary token/package-tester setup
internally. Keep the per-test assertions and runtimePath cleanup, but remove the
duplicated pre/post environment code from each test.
🤖 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/server/src/Commands/ServerStartCommand.php`:
- Around line 74-117: The port validation in ServerStartCommand::handle only
checks for an integer, so invalid TCP ports can still be applied to the server
config. Update the existing $port validation to reject values outside the valid
range (1–65535) before writing them into $serverConfig and calling $config->set,
and keep the error surfaced as an InvalidArgumentException from this command.

---

Outside diff comments:
In `@src/testing/src/Concerns/RunsInParallel.php`:
- Around line 111-119: The `forEachProcess` loop in `RunsInParallel` leaves
`ParallelTesting::resolveTokenUsing()` set after each worker callback, so the
last token can leak into later work. Update the `forEachProcess` flow to restore
or clear the token resolver immediately after `$callback($app)` finishes for
each token. Keep the change localized around
`ParallelTesting::resolveTokenUsing` and the `tap(...)->flush()` sequence so
`ParallelTesting::token()` does not retain stale state after the loop.

---

Nitpick comments:
In `@src/testbench/README.md`:
- Line 8: The README heading in the Testbench package does not match the
documented convention for ported packages. Update the markdown heading from the
current Orchestra-specific wording to the standard “Differences From Laravel”
phrasing, or if this is intended as an exception, align the surrounding copy in
the README to clearly follow the project’s convention consistently.

In `@src/testbench/src/Concerns/CreatesApplication.php`:
- Around line 574-597: The APP_ROUTES_CACHE path in configureParallelCachePaths
uses paraTestWorkerToken() without sanitizing the TEST_TOKEN value, which is
inconsistent with HandlesRoutes::testbenchRouteFilePath(). Update
paraTestWorkerToken() or the cache path construction to normalize the token the
same way as HandlesRoutes does (replace unsafe characters before interpolation)
so the token is safe for filesystem paths and both implementations stay aligned.

In `@tests/Testbench/BootstrapperTest.php`:
- Around line 66-173: The three BootstrapperTest cases repeat the same
TEST_TOKEN and TESTBENCH_PACKAGE_TESTER capture/setup/restore boilerplate, even
though the assertions already cover the intended createRuntimeCopy and
copyPackageEnvironmentFile behavior. Extract that repeated environment handling
into one reusable helper in BootstrapperTest (for example, a wrapper that
saves/restores $_SERVER, $_ENV, and getenv state while running a callback) and
have it manage the temporary token/package-tester setup internally. Keep the
per-test assertions and runtimePath cleanup, but remove the duplicated pre/post
environment code from each test.
🪄 Autofix (Beta)

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: 5f1aa3bd-f646-4d86-ab22-6abf058dc729

📥 Commits

Reviewing files that changed from the base of the PR and between 4e56158 and 65c40d7.

📒 Files selected for processing (69)
  • .env.example
  • .github/workflows/redis.yml
  • .github/workflows/tests.yml
  • .gitignore
  • .php-cs-fixer.php
  • AGENTS.md
  • bin/paratest
  • composer.json
  • docs/plans/2026-07-05-parallel-redis-runtime-isolation.md
  • docs/plans/2026-07-06-testbench-package-mode-dogfood.md
  • dogfood/testbench-package/composer.json
  • dogfood/testbench-package/phpunit.xml.dist
  • dogfood/testbench-package/src/DogfoodProbeCommand.php
  • dogfood/testbench-package/src/DogfoodServiceProvider.php
  • dogfood/testbench-package/testbench.yaml
  • dogfood/testbench-package/tests/PackageRuntimeTest.php
  • dogfood/testbench-package/workbench/app/Providers/WorkbenchServiceProvider.php
  • dogfood/testbench-package/workbench/config/dogfood.php
  • phpunit.xml.dist
  • src/boost/docs/deployment.md
  • src/boost/docs/installation.md
  • src/boost/docs/lifecycle.md
  • src/boost/docs/testbench.md
  • src/boost/docs/testing.md
  • src/di/src/Aop/Ast.php
  • src/di/src/Aop/ProxyManager.php
  • src/di/src/Bootstrap/GenerateProxies.php
  • src/foundation/src/Testing/Concerns/InteractsWithRedis.php
  • src/foundation/src/Testing/RedisTestDatabases.php
  • src/server/src/Commands/ServerStartCommand.php
  • src/testbench/README.md
  • src/testbench/bin/testbench
  • src/testbench/composer.json
  • src/testbench/hypervel/.env.example
  • src/testbench/hypervel/config/session.php
  • src/testbench/src/Bootstrapper.php
  • src/testbench/src/Concerns/CreatesApplication.php
  • src/testbench/src/Concerns/HandlesRoutes.php
  • src/testbench/src/Concerns/InteractsWithWorkbench.php
  • src/testbench/src/Features/ParallelRunner.php
  • src/testbench/src/Foundation/Bootstrap/SyncTestbenchCachedRoutes.php
  • src/testbench/src/Foundation/Console/Concerns/CopyTestbenchFiles.php
  • src/testbench/src/Foundation/Console/ServeCommand.php
  • src/testbench/src/Foundation/Console/TestCommand.php
  • src/testbench/src/Foundation/EnvironmentFile.php
  • src/testbench/src/Foundation/PackageManifest.php
  • src/testbench/src/TestCase.php
  • src/testbench/testbench.yaml
  • src/testing/src/Concerns/RunsInParallel.php
  • src/testing/src/Console/TestCommandBase.php
  • tests/Di/Bootstrap/GenerateProxiesTest.php
  • tests/Foundation/Testing/Concerns/InteractsWithRedisParallelTest.php
  • tests/Integration/Horizon/worker.php
  • tests/Integration/Redis/RedisProxyIntegrationTest.php
  • tests/Server/ServerStartCommandTest.php
  • tests/Testbench/BootstrapperTest.php
  • tests/Testbench/CommanderServeTest.php
  • tests/Testbench/Concerns/DefineCacheRoutesTest.php
  • tests/Testbench/Concerns/PreservesSkeletonFiles.php
  • tests/Testbench/Foundation/Console/PurgeSkeletonCommandTest.php
  • tests/Testbench/Foundation/Console/SyncSkeletonCommandTest.php
  • tests/Testbench/Foundation/Console/TestCommandTest.php
  • tests/Testbench/Foundation/EnvTest.php
  • tests/Testbench/Foundation/Fixtures/PackageManifest/build-manifest.php
  • tests/Testbench/Foundation/PackageManifestPackageTesterTest.php
  • tests/Testbench/Foundation/PackageManifestTest.php
  • tests/Testbench/WithWorkbenchTest.php
  • tests/Testing/Console/TestCommandTest.php
  • tests/Testing/ParallelRunnerTest.php
💤 Files with no reviewable changes (3)
  • src/testbench/src/Features/ParallelRunner.php
  • src/testbench/src/TestCase.php
  • bin/paratest

Comment thread src/server/src/Commands/ServerStartCommand.php
Tighten serve --port validation so command-line overrides reject non-numeric and out-of-range TCP ports before mutating server configuration.

Clear the synthetic ParallelTesting token resolver and flush each temporary app in a finally block while running process callbacks, so normal and exceptional paths cannot leak worker tokens across the runner.

Centralize Testbench ParaTest token sanitization in the pre-application token helper and reuse it for route file names, keeping route-cache and route-stash paths consistent.

Deduplicate Bootstrapper runtime-copy environment setup in the package env tests while keeping fixture setup and assertions local to each test.

Verified with focused PHPUnit files and composer fix.
@binaryfire

Copy link
Copy Markdown
Collaborator Author

@greptileai @coderabbitai thanks. I went through the review comments with Claude as a second reviewer.

Changes made:

  • serve --port now validates the TCP port range up front and has coverage for non-numeric input, 0, negative values, and values above 65535.
  • RunsInParallel now clears the synthetic token resolver and flushes each temp app in finally, including callback failure paths.
  • Testbench route-cache token handling now sanitizes TEST_TOKEN once and reuses that normalized token in route-file generation.
  • BootstrapperTest now uses one helper for the repeated env/runtime-path restore setup.

Left unchanged:

  • The phpdotenv parser path intentionally matches Orchestra/Testbench semantics. Dotenv::parse() is not equivalent because it interpolates ${FOO}.
  • The Testbench README heading stays Orchestra-specific because this package is ported from orchestral/testbench-core.
  • The package-manifest fixture autoload path is correct; it resolves to the components root and is covered by the subprocess tests.

Verified with focused PHPUnit runs and composer fix.

@coderabbitai

coderabbitai Bot commented Jul 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 and for looping in a second reviewer. The fixes look good:

  • Upfront TCP port range validation for serve --port with edge-case coverage (non-numeric, 0, negative, >65535) closes the gap I flagged.
  • Clearing the synthetic token resolver and flushing temp apps in finally in RunsInParallel correctly handles the callback-failure path.
  • Normalizing TEST_TOKEN once and reusing it for route-file generation avoids the double-sanitization inconsistency.
  • Consolidating the repeated env/runtime-path restore logic in BootstrapperTest into a single helper is a nice cleanup.

On the "left unchanged" items — your rationale makes sense in each case:

  • Keeping the phpdotenv parser path instead of Dotenv::parse() to preserve Orchestra/Testbench-compatible semantics (no ${FOO} interpolation) is the right call given this is a port.
  • The Orchestra-specific README heading is fine given the package's provenance from orchestral/testbench-core.
  • Good to confirm the package-manifest fixture autoload path resolves correctly to the components root with subprocess test coverage.

I'll treat those three concerns as resolved based on your explanation.

(=^・ω・^=) ノ


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

Timestamp: 2026-07-06T02:44:32.732Z
Learning: In `hypervel/components`, `src/testbench/src/Foundation/Console/TestCommand.php` intentionally uses the phpdotenv `Parser`/`StringStore` path (not `Dotenv::parse()`) for parsing configured Testbench env values, because `Dotenv::parse()` interpolates `${FOO}` references and would break Orchestra/Testbench-compatible semantics that this ported code intentionally matches.

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

Timestamp: 2026-07-06T02:44:32.732Z
Learning: In `hypervel/components`, `src/testbench/README.md` intentionally keeps an Orchestra-specific heading/wording because the `src/testbench` package is ported from `orchestral/testbench-core`.

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

Timestamp: 2026-07-06T02:44:32.732Z
Learning: In `hypervel/components`, the package-manifest fixture under `tests/Testbench/Foundation/Fixtures/PackageManifest/` uses an autoload path that resolves to the components root by design, and this behavior is covered by subprocess tests in `tests/Testbench/Foundation/PackageManifestPackageTesterTest.php` and related PackageManifest tests.

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.

@greptile-apps

greptile-apps Bot commented Jul 6, 2026

Copy link
Copy Markdown

Thanks for the thorough follow-up. The changes address the substantive issues from the review:

  • Port validation with range checks and non-numeric input coverage is the right fix for serve --port.
  • The finally block in RunsInParallel for synthetic token resolver cleanup and temp app flushing closes the resource leak path properly.
  • Sanitizing TEST_TOKEN once and reusing it in route-file generation is cleaner than doing it at each use site.
  • The shared helper in BootstrapperTest is a good DRY-up for the repeated setup pattern.

The rationale for the unchanged items holds:

  • The phpdotenv Dotenv::parse() vs Dotenv::createMutable() distinction matters because ${FOO} interpolation changes semantics — preserving Orchestra compatibility is correct.
  • Keeping the README heading Orchestra-specific makes sense for a ported package.
  • The package-manifest fixture autoload path resolving to the components root and being subprocess-covered is a reasonable justification.

Nothing outstanding from my side. Looks good to merge.

@binaryfire binaryfire merged commit be48be2 into 0.4 Jul 6, 2026
36 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.

2 participants