Repository navigation
Compatibility and release preparation for 1.0.0 - #8
Merged
Merged
Conversation
…heuristic strip (D66)
…a page listed again
…nd clock functions
…d-hosting functions
…ollector gaps, and accept PHP 8.6's cURL option message
Laravel's HandleExceptions logs a deprecation and turns any other issue into an exception that a request answers with an error, so a notice, warning or deprecation that a file of src/ raises during a request never reaches PHPUnit. After each Laravel application and Symfony kernel of the bridge test cases boots, SrcErrorGuard puts a handler in front of the framework's: it records such an issue with its file:line and still hands it to the framework's handler. tearDown() puts the handler stack back and fails the test with every recorded issue. The warm-up shares the guard's rule for what counts as an issue of src/.
The test timed the collection of a finished transfer against 0.5 s, less than the 1 s of slack the timing tests keep. A time cannot tell the fix from the bug with that slack: without the fix, a finished transfer waits one wait at most, and a wait ends after 1 s. The test now asserts an order: after every start() and pump(), libcurl holds no finished transfer that the transport has not read, and the fast transfer is collected while the other one is still in transfer. That other transfer goes to a local server that never answers, so it cannot hold a worker of the mock collector. The loop stops before its last wait, which saves 1 s. Reading libcurl's queue needs the transport's multi handle, so the one helper that reads it may use reflection.
A single wait of 0.2 s with a transfer in progress returned after 0.149 s on PHP 8.6 with libcurl 7.88.1: libcurl ends a wait at a timer of its own (one due about 200 ms after the transfer starts), and until a curl_multi_exec() runs that timer, every later wait returns at once. The test now counts waits: pump() and a wait of 0.2 s, for 0.6 s, run about three times, where a wait that does not block runs about 100 000 times. Ten waits with a NaN or a negative bound, each after a pump(), take less than 1 s, where a wait of the maximum takes 10 s.
…the timing fixtures - The guard goes in front of Laravel's error handler before the providers register (Testbench resolves RegisterProviders right after HandleExceptions) and in front before a Symfony kernel boots, so a deprecation in AgentCat's provider or bundle fails the test. A test provider and a compiler pass check the position; one guard fronts each application handler, never two. - The guard's assertion runs in an After hook, after every tearDown() of the test, so its failure skips no subclass cleanup. The handler stacks go back in a finally, and setUp() forgets what a test that threw before its assertion left. - UnreadTransfers fails closed: a member that is not what the transport keeps there throws a LogicException that names it. - The positive-wait check allows fewer than 8 passes in 0.6 s, not 20. - SrcErrorGuardTest covers a handler that declines the issue and no handler at all: both give the issue to PHP's own handling. - The slow export of EventQueueDeliveryTest goes to a local server that never answers, so no mock collector worker serves the event after it.
…ssert the context requirement and the get_more_tools description
…one application process
…kstarts and a parity check
…runtime notes, and pin the README outline and reference links
An exit-2 reason (an unreadable snapshot, a wrong argument) went to STDERR only, so the nightly issue said nothing about it. The step now captures both streams, as the branding-drift step does.
…rt() may already have filled Process::start() ends with one read of the pipes, into the output buffer only. When the test process lost the CPU inside start() on a loaded host, the fixture printed "signaled" before that read, the waitUntil() callback never saw it, and waitForLine() returned false when the 5 s drain ended. waitForLine() now checks the buffer, then waits for the rest. With the test process held for 0.5 s inside start(), the three tests that wait for a line failed before the fix and pass after it; 20 runs in a row pass under one busy loop per core.
…ravel Boost guidelines CHANGELOG.md follows Keep a Changelog 1.1.0, with the 1.0.0 features under Unreleased and the B10 change with its cost. CONTRIBUTING.md is the TypeScript guide with the PHP commands and the one required check, All green; it stays out of the dist. composer.json takes the TypeScript package's description and keywords, plus php, laravel, symfony and mcp-sdk. resources/boost/guidelines/core.blade.php tells the AI agent of a Laravel application how to install, configure and test AgentCat. The package probe now requires exactly the expected top-level entries of the dist.
Every comment in src/ and tests/ now states, in plain words, the rule or the reason it relies on. Decision IDs (D07), bug IDs (B10) and criterion IDs (ac-05-E5) stay. CapturingCallTool names the tested laravel/mcp versions, 1.0.0 to 1.1.0. Outside comments, unused test group attributes go, and three dataset names and one assertion message are reworded; no src/ code changes. PackageFilesTest guards the committed text of src/, tests/, config/, resources/, .github/, README.md, CHANGELOG.md and CONTRIBUTING.md, a reference that wraps onto the next comment line included.
…he criteria list does
The guard pattern is case-insensitive, and it now reads recipe/ and every committed root file. An explicit list allows the ordinary phrases it would otherwise flag: MCP's own tasks ("task 2 of an MCP server", "task 2 is cancelled") and another document's appendix. A data provider holds positive and negative examples. Comments spell a criterion as the criteria list does (ac-03-11).
Comments only in src/: the docblocks are reflowed, the drift reason is stated once in Drift, and CapturingToolInvoker names laravel/mcp 1.1.0. The package probe lists the dist's top-level entries with bash globs instead of GNU find's -printf.
…ignoring every unknown App class
Composer's pretty version of a tag keeps the tag's v (v0.9.0). The log prefix, the diagnostics attributes, the events and the User-Agent now carry the bare version (0.9.0), as the TypeScript SDK names versions, so one release has one value across SDKs.
The changelog names no Symfony Flex recipe: the recipe reaches Flex after the release. The tools/list line says in a customer's words that a tool on a later page keeps its own parameters, that under per-request runtimes the server's own tools/list handler runs once for each page read during a tools/call, and what that costs, without IDs a reader cannot look up. The contributing guide answers issues and pull requests as soon as we can, with no deadline (D70).
A customer's get_more_tools on a page before the last made the last page append AgentCat's too, so a client saw two tools of that name. A tracked server now remembers a page that named the customer's tool and appends nothing to its last page. A process that never read that page, every request under PHP-FPM, cannot know it: the shadowing warning now says that AgentCat's tool is then listed too, on the last page, and to rename the customer's tool.
…line With usleep() disabled, a wait for a retry threw inside the transport's guard, and the delivery loop ran hot until its deadline: about 590,000 passes in the 5 s shutdown budget of a request whose event API failed. A wait now sleeps with usleep(), or with time_nanosleep() where usleep() is disabled. Where both are disabled, the wait says it cannot block, one line per process says why, and the delivery ends at the first retry that is not due yet.
…es only A customer's project takes stable releases: with minimum-stability dev, a dependency that has only dev releases would pass the probe and fail for customers. The release legs now resolve with stable, and only the dev-main leg keeps dev.
…ges off STDOUT The dev-main jobs write PHPUnit's failures, STDERR included and without colors, to a report that the issue step appends, as the snapshot and branding jobs do, so the issue names the failing test. The PHP nightly job prints PHP's own messages to STDERR: a dependency's deprecation can no longer break the tests that send headers, and the log still shows it.
…d alone The early return after the customer's own tool had become a second way to the same answer: the record of that tool already keeps the last page free of AgentCat's.
…eline opis/json-schema calls spl_object_hash(), which PHP 8.6 deprecates. PHPUnit counts the deprecation, and failOnDeprecation fails the PHP 8.6 and PHP nightly jobs although every test passes. These two jobs now read phpunit-baseline.xml, which lists only that line. Every other deprecation still fails them. The baseline stays in the repository root, because PHPUnit joins the baseline's directory and each path without resolving "..". It is not in phpunit.xml.dist, because Infection copies that file to a temporary directory without rewriting the baseline path. A test reads the file, so a broken baseline fails on every PHP version, not only in the PHP 8.6 jobs.
kashishhora
approved these changes
Oct 22, 2026
Base automatically changed from
feat/plan-e2-symfony-runtime
to
feat/plan-a-foundation
October 22, 2026 22:59
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Eighth part of the PHP AgentCat SDK: compatibility and release preparation for 1.0.0. Stacked on #7; review #1 to #7 first. The PHP pages of docs.agentcat.com are in agentcathq/agentcat-ui#253.
SDK changes
tools/listpage is read. When a server pages its tools (laravel/mcppages 15 at a time), AgentCat now reads pages until it finds the called tool, so a tool on a later page keeps its ownsession_idorcontextargument instead of falling back to the heuristic strip. The rebuild stops at a repeated cursor, after 100 pages or after 5 s, and logs one line. This differs from the TypeScript SDK on purpose. Cost under PHP-FPM: a call for the last-page tool of a 300-toollaravel/mcpserver takes 57.6 ms (2.7 ms before); a page-1 tool costs the same as before. The customer's owntools/listhandler runs once for each page read.mcp/sdk0.9.0 is supported and tested next to 0.8.1 (a CI job withoutsymfony/mcp-bundle, which still requires 0.8.x).disable_functions(curl_multi_*,pcntl_*,posix_*,getenv,putenv,register_shutdown_function,set_time_limit,ignore_user_abort,hrtime,ini_set,usleepand more), the server keeps answering with no fatal error, and each degraded feature logs one line per process. A failure that repeats in every delivery pass logs once with a count. Withoutcurl_multi_*, AgentCat cannot send events: the runtimes page says so.track()on theMcp\Serverthat a trackedBuilderbuilt returns it as already tracked, with the TypeScript SDK's log line, instead of logging a failure.get_more_toolsis no longer followed by a second one from AgentCat in the same process.mcp=0.9.0,sdk=1.0.0), as in the TypeScript SDK.agentcat/api~0.0.4, whose models list theagentcat:customevent type; a test fails if the SDK sends an event type that the models do not list.Package
mcp/sdk, Laravel and Symfony. A test keeps the shared sections, the images, the links and the PHP samples in step, and a nightly job compares them with the TypeScript repository.CHANGELOG.md(Keep a Changelog),CONTRIBUTING.md, the Composer description and keywords of the TypeScript package, and Laravel Boost guidelines inresources/boost/guidelines/core.blade.php.CI
staticruns both PHPStan configurations;static-lowestruns them on the lowest dependency set; PHP 8.6 runs as an experimental job.phpunit-baseline.xml, which ignores one deprecation insideopis/json-schema(spl_object_hash(), deprecated in PHP 8.6). Every other deprecation still fails them, and a test reads the baseline on every PHP version.package: installs the package as Packagist ships it (git archive, soexport-ignoreapplies) into a fresh project withmcp/sdk0.8.1 and 0.9.0, and proves that one tool call answers and delivers one event to a local collector.bc: Roave's backward-compatibility check against the latestv1.*tag (it passes until 1.0.0 exists).mcp/sdk,laravel/mcpandsymfony/mcp-bundleatdev-main, PHP nightly, the full mutation run,composer audit, the live OpenAPI schema tests, the runtime suite on the latest image patches, the package probe onmcp/sdkdev-main, a snapshot of every member of the upstream classes AgentCat reads (a changed member it reads fails by name), and the README drift check. Each failing job opens onenightlyissue, or comments on the open one, with the failing tests or members in the issue. This pull request runs it once, because it adds the workflow.Tests
php -Slanes.src/, including during provider and bundle boot.mcp:servercommand draining on SIGTERM, a PHP-FPM pool with a shared-hostingdisable_functionslist, and timing tests hardened against load.Testing
3475 tests pass (
composer check; two expected skips). The covered mutation score is 98.65 % on the full set and 99 % on the lines changed since #7. Themcp/sdk0.9.0 leg passes with 901 tests, the package probe passes for 0.8.1, 0.9.0 anddev-main, and the runtime suite passes with 62 tests in Docker. PHP 8.5 with the highest set (PHPUnit 13.4.3) and the lowest set passed locally in Docker: both PHPStan configurations and the full suite. laravel/mcp 1.1.0 (released 2026-10-20) passes.After the merges
Tag
v1.0.0onmainonce #1 to #8 and agentcat-ui#253 are merged and you approve it; then the Symfony Flex recipe pull request to symfony/recipes-contrib (its text goes to you first) and the PHP lanes of the health harness.