Repository navigation
feat: publishCustomEvent, AgentCat::fake(), signal drain and end-to-end tests - #4
Merged
naji247 merged 17 commits intoOct 22, 2026
Merged
Conversation
…rver after a failed track A track() that AgentCat could not complete (mcp/sdk drift, an unsupported shape, an internal failure) or an unreadable built server now marks the process. publishCustomEvent() then logs one warning per call for a server it cannot find instead of throwing into the customer's code; without such a failure it still throws like TypeScript. The drift cases that need ReflectionClass move to the contract tests, and the PHPDoc says how a coercive caller's scalar first argument is read.
… one shutdown budget per queue
… server bounded and local
PHP 8.5 warns when it casts such a float to int, and a CLI server prints that warning on STDOUT. A NaN, an infinity or an out-of-range float now leaves the duration out on PHP 8.3, 8.4 and 8.5 alike.
A later shutdown() (the shutdown function after a signal drain that used the whole budget) still ran one pump: hooks for up to 5 waiting events and up to 5 transfers that the process abandons at once. Once the deadline of the first shutdown has passed, a later one only reports the events that still wait.
An ignore inherited from the parent process reads as SIG_DFL in PHP, so AgentCat installs its drain for that signal. No behavior change.
AC-69 is "a high-level server whose low-level server is tracked is accepted". These tests cover D31, D44 and ruling R4, which have no acceptance criterion; PublishCustomEventTest keeps the AC-69 tag.
Under AgentCat::fake(), track() and publishCustomEvent() wrote to $HOME/agentcat.log on every developer machine and CI runner, and a Builder's PSR-3 logger tracked under the fake took every later AgentCat line of the suite. While a fake's client is the shared client, AgentCat now logs to that fake only (AgentCatFake::logs()) and adopts no Builder logger. AgentCat::setClient() that replaces it brings back the routing from before the first fake().
In a test environment, a server that the application tracks in setUp(), before the test calls AgentCat::fake(), is not tracked at all. Code under test that then published a custom event for it got the TypeScript "Server is not tracked" exception. track() now records, process wide, that it ran while AgentCat was off; publishCustomEvent() then logs a warning that says to call fake() first (the failed-track line keeps precedence), and assertTracked()/assertTrackedCount() add the same hint when no tool call was recorded. The fake() PHPDoc says to call it before the application builds its servers.
kashishhora
approved these changes
Oct 22, 2026
Base automatically changed from
feat/plan-c1-adapter
to
feat/plan-a-foundation
October 22, 2026 22:55
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.
Fourth part of the PHP AgentCat SDK: the rest of the public API and end-to-end tests. Stacked on #3; review #1, #2 and #3 first.
What is in it
AgentCat::publishCustomEvent($serverOrSessionId, 'proj_…', new CustomEvent(...))with the TypeScript server and session-string forms. The server form accepts the Builder or the builtMcp\Server, uses the tracked project and server info, and appliesredactEventonly. The two TypeScript validation errors throw\InvalidArgumentException; when AgentCat itself could not track the server (an mcp/sdk change, ortrack()ran while AgentCat was off), it logs one warning instead of throwing.AgentCat::fake()for customer test suites:events(),logs(),assertTracked(),assertTrackedCount(),assertNothingTracked(),assertCustomEventPublished(). No network, hooks applied, each passing assertion counts as one PHPUnit assertion, and AgentCat's log lines stay in memory instead of~/agentcat.log.SIG_IGNset in PHP. A second signal acts at once.shutdown()and the shutdown function.durationis sent as no duration (no PHP 8.5 warning on STDOUT).composer.jsonsuggests ext-pcntl and ext-posix.Testing
1735 tests pass (
composer check; two expected skips). Full mutation score 98.4 %, covered MSI on changed lines 100 %. New E2E suite: a realmcp/sdkserver underphp -Sand as a stdio subprocess, raw JSON-RPC, a local mock collector; it proves the response does not wait for the hooks, stdout stays pure JSON-RPC, EOF and SIGTERM delivery within the 5 s budget, and a fiber suspended inside AgentCat's interceptor. Themcp-sdk-mainjob now runs Contract, Integration and E2E againstmcp/sdkmain at82e19d1. PHP 8.5 with the highest and the lowest dependency sets passed locally in Docker (PHPStan and PHPUnit).