studio-design/gesso
Gesso is a Laravel package for building responsive, email-safe templates with Tailwind CSS. It provides Blade components and helpers to assemble transactional emails quickly, keeping markup consistent and compatible across common email clients.
Scope of this release: v2.7.0 is a minor release (no BREAKING CHANGE footer) delivering 12 features and 7 fixes across configuration, adapters, CLI, validation, and CI integration. Gesso presents as a spec/contract-testing toolkit for PHP — OpenAPI-driven request/response validation, HTTP client fakes for consumer-side contract tests, route parity checks for Laravel, and coverage merge/gate commands — wired into PHPUnit/Pest via an extension and into Laravel via a service provider. Verdict: adopt/upgrade, but stage the two behavior-tightening changes separately from the config migration.
Architecture fit
config: share configuration between phpunit and laravel (#593) is the architectural centerpiece. A single gesso.php consumed by both the PHPUnit extension and the Laravel package removes the classic drift failure where local runs and CI enforce different rules. This is a genuine structural improvement, not a convenience.laravel: read route-side parity exclusions and the spec list from config (#621) moves routing exclusions out of code and into declarative config. Good for auditability, but it deepens coupling to Laravel's router internals — the Laravel major-version support matrix becomes a first-order compatibility concern.adapters: default the symfony and psr-7 policy hooks from the shared configuration (#614) adopts inheritance over per-adapter declaration. Compositionally cleaner; operationally it introduces an implicit surface where an adapter picks up global policy hooks that were previously absent. Silent inheritance is the highest-value item to test explicitly.Integration feasibility
doctor: emit an equivalent gesso.php with --emit-config (#627) is effectively a migration tool: generate the new shared config from existing state rather than hand-authoring it. Combined with --format and --output-file on every subcommand (#620) and config-defaulted coverage:merge/coverage:gate (#626), this release is unusually well-set-up for incremental adoption.contract: move named contract checks to the Contract namespace behind a deprecated Fuzz alias (#608) — deprecation-only, no removal announced.Technical risk: Low–Medium
validation: decode adapter JSON bodies as objects so a nested {} is not read as [] (#561) — empty-object vs empty-array distinctions now matter. Contracts or fixtures that passed by conflating the two will start failing.validation: honor form encoding style, explode, and part headers (#619) and validation: preserve body boundaries across adapters and doctor (#566) — stricter, more spec-faithful multipart handling. Correct, but it converts previously-tolerated spec looseness into red builds.adapters policy-hook defaults (#614) — behavioral, and potentially affects any non-test code path that uses the adapters.enum-drift once per paratest run (#613) is a pure CI-time win; phpunit: tolerate the sealed event facade in the pest --parallel orchestrator (#599) is a stability fix; config: lower-case setting values without ext-mbstring (#570) implies mbstring is optional and only affects non-ASCII setting values; docs advisory bumps (#601) are dev-only.Key questions for the maintainers
#614 is a runtime behavior change requiring a change-control review, not a dev-dep bump.gesso.php, phpunit.xml, extension parameters, and CLI flags? #593 and #626 both introduce config-sourced defaults; ambiguity here produces local/CI divergence.--emit-config lossless and idempotent — does it round-trip an existing phpunit.xml + extension setup without dropping settings?Fuzz alias removal scheduled for a specific major, and is there a deprecation-notice mechanism that will fail builds under strict error handling?#561 change documented comparison semantics, and is there a migration note or opt-out flag for teams that intentionally used [] to mean "any empty"?#600) conflict with project- or monorepo-level analysis pins?Stack fit
Migration path (config-first, additive)
gesso doctor --emit-config to generate a candidate gesso.php.phpunit.xml and current extension parameters; reconcile deliberately, recording any setting that has no equivalent.#593) with validation behavior otherwise unchanged — this is the isolated step.#561, #566, #619) and triage resulting failures as either spec defects or over-strict assertions.--format/--output-file (#620) into CI reporting so results are machine-readable.coverage:merge/coverage:gate defaults (#626) only after confirming they reproduce current gate behavior exactly.Contract namespace rename; keep the Fuzz alias and track its removal.Compatibility checks before merge
#599 resolves rather than masks the sealed-facade issue in your Pest version.#570 covers your setting values.composer.lock resolution against the newly pinned dev analysis tools (#600).Sequencing caution: do not land the config unification and the validation-fidelity adoption in the same change. They are independent failure sources, and combining them makes triage of a red build materially harder.
Gate criteria: two consecutive green full runs (serial and parallel) on the new config, plus an exact match on prior coverage gate outcomes.
Maintenance
Contract namespace deprecation creates a standing inventory item. Track every Fuzz\ reference in your codebase so the eventual alias removal is a scheduled cleanup, not an outage.#600) improve reproducibility but can conflict with monorepo-wide pins; check dependency resolution at the root, not just per-package.Support
Scaling
enum-drift evaluated once per paratest run (#613) is a direct CI-time saving that compounds with suite size — quantify it during the pilot to build the case for broader rollout.Failure modes to watch
#614) causing over- or under-enforcement with no explicit signal.#561) presenting as intermittent, hard-to-attribute test failures.--output-file artifacts being committed accidentally; add ignore rules up front.#621) drifting from the actual spec without review.Rollback
#561/#566/#619 — snapshot assertion output before and after so a rollback of the package version also restores expected results.Ramp-up
doctor plus --emit-config substantially shortens time-to-first-green.How can I help you explore Laravel packages today?