Add ! as an explicit strict modifier to named expression signature contracts.
%define :text! :> short-name(length -> :integer! = 3) -> :text! =
upper | first-chars(@length);
Acceptance criteria:
- Support strict pipeline input, explicit parameter, and output contracts independently and in combination with ordinary coercing contracts.
- A strict contract checks compatibility without conversion, using is-type semantics and canonical type-family relationships rather than exact underlying runtime-type equality.
- A mismatch raises a contract error identifying the named expression, boundary/parameter, expected type, and actual type. Reject statically invalid contracts during binding where possible; runtime mismatches are evaluation errors.
- Strict :integer! accepts integer 5 and rejects text "5" and #null. An omitted parameter still uses its default, which must satisfy the contract.
- Strict :numeric! accepts values belonging to the numeric family.
- Errors stop evaluation; they are not #null/#false results and are not guard-style input preservation.
- Keep :type descriptors and existing coerce(:type)/is-type(:type) behavior unchanged. ! modifies the signature contract; it is not a new global behavior for type descriptors.
- Cover mixed strict/coercing boundaries, type families, null, defaults, failure diagnostics, and scope restoration.
- Document strictness separately from nullability and optionality; nullable contract syntax remains deferred.
Stage 7 of 8. Depends on #999.
Add ! as an explicit strict modifier to named expression signature contracts.
Acceptance criteria:
Stage 7 of 8. Depends on #999.