# @systemfsoftware/oxlint-plugin-effect-schema

## 6.0.0

### Major Changes

- Rules recognize effect 4.0.0 module paths: `effect/Arbitrary` (and the root `Arbitrary` name), `effect/process/ChildProcessSpawner`, and the `effect/encoding` codecs. A module is judged the same whether it is imported from `effect`, from an `effect/<area>` barrel, or by its own subpath. `schema-file-imports-pure-modules-only` admits `Base64`, `Base64Url`, `Hex` and `EncodingError` from `effect/encoding` in place of the removed `Encoding` module.

- Require `effect` `^4` (stable 4.0.0). Release candidates are no longer supported: imports follow 4.0.0's module layout (`effect/http`, `effect/rpc`, `effect/http-api`, `effect/cluster`, `effect/process`, `effect/socket`, `effect/persistence`, `effect/reactivity`, `effect/encoding`, `effect/Arbitrary`), which does not exist in any 4.0.0 RC.

## 5.7.0

### Minor Changes

- New `schema-file-imports-pure-modules-only` rule, enabled in the recommended config: a schema file may value-import only Effect's pure modules, its schema modules, `effect/Effect`, `effect/unstable/arbitrary`, other schema files and `@systemfsoftware/*` packages, and a dynamic `import()` or `require()` reaching outside that set is reported too, including one whose source is not a string literal and so cannot be proven pure. `schema-file-exports-schemas-only` now accepts what a schema file owns besides its schemas: an exported function or `dual` const whose declared parameter or return type names a type declared in the same file and that returns no `Effect`, `Stream` or `Layer`, read through unions, type predicates, type parameter constraints and readonly arrays; a type-only namespace; a `Symbol.for('<literal>')` type identity; and a constant annotated with a same-file type.

## 5.6.0

### Minor Changes

- New `tagged-error-requires-message` rule, enabled in the recommended config: a `Schema.TaggedError` class must declare a `message` field or a `message` getter.

### Patch Changes

- `schema-declaration-location`'s fix text no longer sends authors to `tests/__fixtures__/<stem>.schema.ts`. It names the production module that owns the concept, or the test harness file (`*.model.ts` or `*.fixture.ts`) for a harness schema.

## 5.5.2

### Patch Changes

- Update peer and runtime dependency on `effect` and companion packages to `4.0.0-rc.117`.

## 5.5.1

### Patch Changes

- Bump the stryker catalog to pull in the latest patch releases of the stryker-js ecosystem.

## 5.5.0

### Minor Changes

- The `schema-filter-constructive-generation` rule distinguishes scalar and struct receiver chains: `arbitrary: { candidate }` no longer satisfies the rule on any receiver, struct filters are permitted without annotations because Effect v4 provides no compiler hook for constructive cross-field filter generation, and node `toCodecArbitrary` overrides only silence the rule on `Schema.declare` receivers where the compiler honors them.

## 5.4.0

### Minor Changes

- A `recursionBudget` annotation materializes as `toCodecArbitrary`. Replace a hand-written `toArbitrary` derivation with `toCodecArbitrary`. Generation depth follows `maxDepth`.

## 5.3.2

### Patch Changes

- `schema-declaration-location` now judges runtime code only — a file in the package's source directory, or a test file. A module-scope schema in a package-root hook, config, or setup file is outside its subject and no longer reports.

## 5.3.1

### Patch Changes

- Releases the workspace so its published versions track the shared dependency graph this change moves.

## 5.3.0

### Minor Changes

- Two shapes now fail a rule in the recommended set.

  A recursive schema union whose cycle carries six or more separately suspended members derives arbitrary values superlinearly; hoist the cycle to one `Schema.suspend` at the recursion point, where the members reference the union schema directly.

  A recursion point whose suspension returns a union that reaches itself must declare its ceiling with `recursionBudget` in that suspension's annotation, or carry a hand-written derivation of its own. Without either, the derivation stops at the stock ceiling and never generates the deeply nested values the recursion describes.

## 5.2.0

### Minor Changes

- cut over to effect v4 (4.0.0-rc.108): public surface derives from effect types; peers flip effect ^3→^4

### Patch Changes

- New version is published through npm trusted publishing, so it carries a provenance attestation you can verify.

- Peer Effect requirement advances to 4.0.0-rc.112. No API changes.

## 5.1.0

### Minor Changes

- A new recommended rule, schema-filter-constructive-generation, reports an Effect Schema filter that carries no constructive generation hint when it is used in a check or exported from a module. Add arbitrary.constraint or arbitrary.candidate to the filter, or give the schema a toArbitrary override before the check, to clear the report.

- A new recommended rule, schema-checked-element-named, reports a checked schema node passed inline as a collection combinator element. Bind the checked chain to a module-scope const and pass the name to the combinator to clear the report.

- New rule `schema-filter-constructive-generation` joins the recommended preset. A schema filter declared in the linted file and passed to `.check()` must carry constructive-generation metadata — `arbitrary.constraint` or `arbitrary.candidate` — or the schema must carry a `toArbitrary` override ahead of the check. A filter with neither generates its samples by rejection sampling, so property suites run far below their sampled strength. When the rule fires, add the metadata key your predicate supports; a function-valued `arbitrary` on a filter is the retired replacement form and now reports as well.

## 5.0.1

### Patch Changes

- Re-published against the oxc-based instrumenter: workspace dependency ranges move to the new instrumenter major; no package's own behavior changes in this release.

## 5.0.0

### Major Changes

- The extra entry that asserted a schema rejects invalid input is gone. If you imported it to declare those assertions, drop that import — the package now ships only the round-trip laws.

  The lint rule that forbade restating those round-trip laws in a schema property test is also gone. If you still listed no-schema-law-duplicate among your rules, delete that name.

### Patch Changes

- Peer Effect requirement advances to 4.0.0-rc.112. No API changes.

## 4.0.1

### Patch Changes

- Schema refutation suites are now recognised where schema law suites already were.

  A generated refutation suite may live in source, beside the generated law suite, without being reported as a test file in the wrong place. A block that states a schema's refusals keeps its exemption from the private-target rule, which now recognises the refusal helper at its current import path.

  The duplicate-law diagnostic names that same path when it tells you a hand-written assertion restates a generated law.

## 4.0.0

### Major Changes

- A hand-written `_tag` member in a type is now an error.

  `no-manual-tag-member` reports a `_tag` property signature in any type position — a type alias, an
  interface body, or a type literal inside a union. The diagnostic names the replacement:
  `Schema.TaggedStruct` for a plain variant, `Schema.TaggedError` for an error-shaped one, or
  `Schema.Schema.Type` derivation when the members carry type parameters.

  Before reaching for a replacement, check whether the union is needed at all. Two cases retire it
  outright: no consumer distinguishes the variants, so all but one can go; or every construction site
  already knows which variant it builds, so those operations can be called by name and the union and
  its dispatcher deleted. Where the union survives and its members are encodable, derive the tag from
  a schema. Only where a member cannot be encoded at all — a running effect, a stream, a foreign
  prototype — declare the tag once as a value and let the type inherit it; that form forces no
  constructor and validates nothing, so it is the last answer rather than the first.

  The rule has no options, no allowlist and no per-package disable, and it is on in the recommended
  preset — so upgrading reports every `_tag` member your types declare, in one pass. It is silent in
  `.tst.ts` type-test fixtures, and only there: every replacement it names is a runtime value, and a
  type-test fixture holds none, so firing there could only be answered by a value that exists to be
  read back by `typeof`.

### Patch Changes

- The peer requirements for `effect` and for the Effect test-runner integration now accept any compatible `4.0.0-rc` release, instead of demanding one exact release candidate.

  Installing alongside a newer release candidate no longer reports an unmet peer dependency or resolves a second copy of `effect` into the dependency tree.

## 3.0.0

### Major Changes

- The cell-role suffix rule fleet is deleted, and the aggregate shrinks with it.

  The thirteen plugin packages keyed on the sanctioned cell-role suffixes (`acl`, `adapter`,
  `executor`, `handler`, `kernel`, `middleware`, `observer`, `policy`, `schema`, `shape`, `state`,
  `store`, `workflow`) are gone, so `effect-dmmf` — the aggregate every cell diagnostic is reported
  under — loses those members wholesale, and `effect-schema` loses `schema-exports-only-schemas` and
  `no-manual-tag-member` (`.schema.ts` and `.shape.ts` are in the sanctioned vocabulary). Also gone:
  `effect-workflow`'s four suffix-gated rules. Every representative violation of a deleted class
  compiles clean under strict after the deletion — the refusing channel is none, recorded unowned in
  `docs/solutions/architecture-patterns/cell-suffix-fleet-deleted-unowned.md`. What replaced the
  suffix is the `Workflow.make` boundary: the brand forces the constructor, the lint keys on it, the
  ignorer selects the mutation population from it.

  The thirteen deleted package names should be `npm deprecate`d at publish time (the packages are
  removed from the workspace; their last published versions keep working for existing installs).

  `effect-entrypoint` survives (its rules gate on the `main.ts` basename the taxonomy never owned),
  as do `cell-vocabulary`, `test-placement`, `test-hygiene`, `property-testing`, and core's
  non-filename rules.

### Minor Changes

- cut over to effect v4 (4.0.0-rc.108): public surface derives from effect types; peers flip effect ^3→^4

- Three new rules, a retargeted test-placement taxonomy, and one removal.

  `make-file-location` allows a workflow constructor only in the workflow module that owns it, at most once per module.

  `schema-declaration-location` requires a schema declaration to live in a schema module, or the workflow module that owns it. A binding whose initializer returns something other than a schema — a type guard, a decoder, an encoder, an arbitrary — is a use and is not reported.

  `test-placement` narrows which tests may sit beside source, requires every other test to live in the package test directory, and adds `tests-dir-helpers-in-fixtures`. It also removes `in-source-test-targets-private`, which `effect-dmmf` no longer re-exports — drop the entry if you set it. Each rule reports the exact shape it expects.

### Patch Changes

- Array types are spelled one way. `Array<T>` and `ReadonlyArray<T>` in emitted
  declarations become `T[]` and `readonly T[]`, which the type checker cannot tell
  apart: no exported type changes, only how it is written.

- New version is published through npm trusted publishing, so it carries a provenance attestation you can verify.

- Rescope three rules that over-rejected legitimate files.

  Each was a measured false positive, not a theoretical one — all three fired on files written in the
  course of shipping `Workflow.make`:

  - `cell-suffix-required` rejected `src/Workflow.ts`, a PascalCase contract module whose basename names
    no cell because it _is_ the package's published contract. It now exempts that shape.
  - `no-manual-tag-member`, `no-direct-tag-access`, and `ban-data-taggederror` rejected `**/*.tst.ts`
    type-test fixtures, which must contain no runtime values and therefore cannot use
    `S.TaggedStruct`. The fix each rule suggested was impossible in the file it was suggesting it for.

  This is the cost the cell-taxonomy derivation already prices: a depth-0 rule cannot miss its target, but
  its predicate is a proxy for the property actually wanted, so it over-rejects — and that cost is meant
  to be priced per rule rather than waved away. Three rules, three over-rejections, all rescoped by
  narrowing the predicate; none was deleted and no config was weakened.

## 2.0.0

### Major Changes

- The cell-role suffix rule fleet is deleted, and the aggregate shrinks with it.

  The thirteen plugin packages keyed on the sanctioned cell-role suffixes (`acl`, `adapter`,
  `executor`, `handler`, `kernel`, `middleware`, `observer`, `policy`, `schema`, `shape`, `state`,
  `store`, `workflow`) are gone, so `effect-dmmf` — the aggregate every cell diagnostic is reported
  under — loses those members wholesale, and `effect-schema` loses `schema-exports-only-schemas` and
  `no-manual-tag-member` (`.schema.ts` and `.shape.ts` are in the sanctioned vocabulary). Also gone:
  `effect-workflow`'s four suffix-gated rules. Every representative violation of a deleted class
  compiles clean under strict after the deletion — the refusing channel is none, recorded unowned in
  `docs/solutions/architecture-patterns/cell-suffix-fleet-deleted-unowned.md`. What replaced the
  suffix is the `Workflow.make` boundary: the brand forces the constructor, the lint keys on it, the
  ignorer selects the mutation population from it.

  The thirteen deleted package names should be `npm deprecate`d at publish time (the packages are
  removed from the workspace; their last published versions keep working for existing installs).

  `effect-entrypoint` survives (its rules gate on the `main.ts` basename the taxonomy never owned),
  as do `cell-vocabulary`, `test-placement`, `test-hygiene`, `property-testing`, and core's
  non-filename rules.

### Minor Changes

- cut over to effect v4 (4.0.0-rc.108): public surface derives from effect types; peers flip effect ^3→^4

- Three new rules, a retargeted test-placement taxonomy, and one removal.

  `make-file-location` allows a workflow constructor only in the workflow module that owns it, at most once per module.

  `schema-declaration-location` requires a schema declaration to live in a schema module, or the workflow module that owns it. A binding whose initializer returns something other than a schema — a type guard, a decoder, an encoder, an arbitrary — is a use and is not reported.

  `test-placement` narrows which tests may sit beside source, requires every other test to live in the package test directory, and adds `tests-dir-helpers-in-fixtures`. It also removes `in-source-test-targets-private`, which `effect-dmmf` no longer re-exports — drop the entry if you set it. Each rule reports the exact shape it expects.

### Patch Changes

- Array types are spelled one way. `Array<T>` and `ReadonlyArray<T>` in emitted
  declarations become `T[]` and `readonly T[]`, which the type checker cannot tell
  apart: no exported type changes, only how it is written.

- New version is published through npm trusted publishing, so it carries a provenance attestation you can verify.

- Rescope three rules that over-rejected legitimate files.

  Each was a measured false positive, not a theoretical one — all three fired on files written in the
  course of shipping `Workflow.make`:

  - `cell-suffix-required` rejected `src/Workflow.ts`, a PascalCase contract module whose basename names
    no cell because it _is_ the package's published contract. It now exempts that shape.
  - `no-manual-tag-member`, `no-direct-tag-access`, and `ban-data-taggederror` rejected `**/*.tst.ts`
    type-test fixtures, which must contain no runtime values and therefore cannot use
    `S.TaggedStruct`. The fix each rule suggested was impossible in the file it was suggesting it for.

  This is the cost the cell-taxonomy derivation already prices: a depth-0 rule cannot miss its target, but
  its predicate is a proxy for the property actually wanted, so it over-rejects — and that cost is meant
  to be priced per rule rather than waved away. Three rules, three over-rejections, all rescoped by
  narrowing the predicate; none was deleted and no config was weakened.
