Skip to content

Monitor 1.0 - #10

Merged
belisarh merged 14 commits into
mainfrom
1.0
Sep 14, 2026
Merged

belisarh merged 14 commits into
mainfrom
1.0

Conversation

@belisarh

@belisarh belisarh commented Sep 14, 2026 •

Copy link
Copy Markdown
Member

Monitor 1.0

A rewrite around the control point, designed from the problem rather than from 0.1. Every operation where failure matters becomes a named declaration of what it tolerates, what bounds it, how every outcome is recorded, and who is told when it fails. Because it is a declaration it can be listed, tested by name, enforced in CI, queried from a log backend, and taught to an agent by the shape of the API.

No compatibility layer. docs/upgrading.md maps every 0.1 surface to its replacement.

What is in the box

  • Control points in two forms, inline (Monitor::control()) and class (ControlPoint + #[Point]), with two terminals: run() returns the value or throws, attempt() returns an Outcome and never throws.
  • Risks and corrections (recover(), the handler's return is the result, null included), escalation (escalate() with a closure or class), limits (within() never fails a completed run, attempts() caps, ensure() fails a wrong result), policies (Retry, Transaction, Breaker, fixed pipeline order, custom via one interface), profiles from config.
  • Nesting with parent run ids, child escalations reaching parent corrections, and retries that never compose across the stack.
  • Records: one schema (monitor/1) for every transition, redacted through Redactor, events first, NDJSON tap, Monitor::log($origin).
  • Tracing on Laravel Context with W3C traceparent, Http::traced(), jobs and console.
  • Breakers with a real closed/open/half-open state machine in the cache, standalone API and route middleware (monitor.breakers).
  • Store of outcomes written after the response, monitor:outcomes, monitor:prune.
  • Verification: Monitor::fake() with eleven assertions, monitor:points --check (table/JSON/SARIF, seven rules), monitor:explain, make:control-point, a Pest expectation and a PHPStan rule.
  • Agents: Boost guidelines shipped in the package, a read-only MCP server (four tools, two resources, one prompt) with JSON-aware redaction.
  • Parity with Redactor: Laravel 12/13, PHP 8.3–8.5, Rector, PHPStan level 10, the same hooks, workflows, docs layout, changelog and upgrade guide.

Conventions pass

After the build, four reviews compared the package against Pennant, Pulse, laravel/mcp and Redactor on code organisation, public API, integration points and documentation. What changed as a result:

  • Interfaces live in Contracts\, commands in Console\Commands\; services are open classes, only value objects are final readonly; exceptions implement a MonitorException marker with their natural SPL parents.
  • Control is Conditionable and Macroable; point names accept backed enums everywhere; policies take constructor arguments; Outcome and the other value objects are Arrayable and JsonSerializable; CircuitBreaker::attempt() is permit().
  • Monitor::fake() implements the framework Fake contract, is idempotent, and has the full positive/negative assertion vocabulary (assertNotRan, assertNotRecovered, assertNotEscalated, assertNotRefused, assertNotRetried, assertRanOnce).
  • The provider is split into registrars behind runningInConsole(), publishes a timestamped migration with publishesMigrations() and never auto-loads it, adds an about section, aliases middleware through callAfterResolving, and has no boot-time side effects: console traces start on CommandStarting, and the store flushes through the HTTP and console kernel lifecycle hooks, queue Looping/WorkerStopping, and a 100-outcome buffer cap, the way Pulse ingests.
  • Redactor calls are guarded so a missing redactor can never fail a control point; MCP tools take dependencies by method injection; an ide.json and a Boost skill (resources/boost/skills/monitor-development/SKILL.md) ship alongside the guideline.
  • Docs: upgrade guide with every 0.1 env var and method, a test-conventions section, BreakerState reference, trimmed README opener, @internal markers on helpers.

After the first review

Nine additions a developer reaches for, plus the queue integration:

  • once($key, $ttl): an idempotency policy with a Duplicate risk, released when the run fails inside its policies and kept once the side effect happened.
  • run() is typed with a template so PHPStan knows the value.
  • Http::breaker('stripe'): the same circuit on the HTTP client, refusing before sending and counting connection failures and 5xx.
  • ChargeCard::dispatch(...): a control point as a job, tagged for Horizon, released for the breaker's retry-after when refused.
  • recover(Risk::class, Handler::class) with a Correction contract resolved from the container.
  • escalateLimits() and throttleEscalation($seconds), with an escalation.throttled record.
  • Monitor::log() binds to the running point; Outcome carries startedAt/endedAt.
  • Jobs start with an empty stack and a dispatched_from_run id; WaitForBreaker job middleware releases instead of failing while a circuit is open. New docs/jobs.md.

Numbers

Tests 231 (1012 assertions), 100% coverage on every matrix leg
Docs 16 pages
Source files 104

Review guide

  1. src/Control.php, src/Run.php, src/Outcome.php are the model; everything else listens to or reads them.
  2. src/Records/Record.php and resources/schema/record-1.json are the log contract.
  3. src/Inventory/ is the static side; src/Testing/MonitorFake.php the test side.
  4. .ai/guidelines/core.blade.php is what an agent reads.

@belisarh
belisarh marked this pull request as ready for review September 14, 2026 19:52
@belisarh
belisarh merged commit cdfbbba into main Sep 14, 2026
19 checks passed
@belisarh
belisarh deleted the 1.0 branch September 15, 2026 03:20
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