What’s New
v2.4.0 is an internal architecture and dependency-hygiene release. It introduces a new low-level package,cognesy/instructor-contracts, and uses it to break a circular
dependency between cognesy/instructor-struct and cognesy/instructor-dynamic. It also
repairs a set of cross-package dependency declarations across the monorepo so that each
package now declares exactly what it uses — which makes standalone (split-package)
installs resolve correctly.
There are no breaking changes to public APIs. Class names and namespaces are unchanged;
the moved contracts keep their existing Cognesy\Instructor\… namespaces.
New package: cognesy/instructor-contracts
A new foundation package holds the small, dependency-light abstractions that several
Instructor packages share — validation, transformation, and deserialization contracts
plus their value objects. It depends only on cognesy/instructor-utils.
Moved into the package (namespaces preserved, so no consumer code changes):
Cognesy\Instructor\Validation\ValidationResult,ValidationErrorCognesy\Instructor\Validation\Contracts\CanValidateSelf,CanValidateObject,CanValidateValueCognesy\Instructor\Transformation\Contracts\CanTransformSelf,CanTransformDataCognesy\Instructor\Deserialization\Contracts\CanDeserializeClass,CanDeserializeSelf
ResponseValidator, ResponseTransformer,
and the *Response contracts) remain in cognesy/instructor-struct.
Broken dependency cycle: instructor-struct ↔ dynamic
Previously instructor-struct and dynamic depended on each other in code (each imported
the other’s classes), which only worked because the monorepo autoloads every namespace.
Both now depend on cognesy/instructor-contracts instead, removing the cycle:
dynamicno longer depends oninstructor-struct.dynamicdeserializes nested concrete-class fields through theCanDeserializeClasscontract, with a self-contained Symfony-based default implementation (SymfonyStructureDeserializer).instructor-struct’sSymfonyDeserializeris unchanged.
Cross-package dependency repairs
cognesy/loggingnaming. Six packages required a non-existentcognesy/instructor-logging; they now correctly requirecognesy/logging. The Laravel package’s stale^1.22constraint on it is aligned to the current line.- Undeclared dependencies. Packages that used a sibling’s classes without declaring a Composer dependency on it now declare it, across 14 packages. This is invisible inside the monorepo but is required for correct standalone installs.
utils↔pipelinecycle.Cognesy\Utils\Strno longer depends on thepipelinepackage; its case-normalization is now dependency-free. The Pipeline-based variant is available asCognesy\Pipeline\Extras\StringNormalizer.
Upgrade notes
No action required. All changes preserve existing class names, namespaces, and public behavior. Standalone consumers of individualcognesy/* packages benefit from the
corrected dependency metadata automatically.