Skip to content

constructor-rule-boundary records sequencing as type-inexpressible, which the Cell phase chain falsifies #163

Description

@systemfsoftware-maker

labels:
priority: p3
type: documentation
area: docs
metadata:
pinned_commit: 1574bfa
learning: docs/solutions/architecture-patterns/constructor-rule-boundary.md

Problem Statement

A recorded learning in this repo states flatly that sequencing is inexpressible at the type level, and that the I/O sandwich order cannot be reached through a constructor. The phase-order work does exactly that: a chain of constructors where each returns a type carrying the member the next one demands, so a wrong order fails to compile. The learning's supporting argument is narrower than its headline -- it reasons about an indexed cell threaded through Effect.gen, where the yielded effects collapse into a union -- but an agent reading the conclusion will re-derive the abandoned negative result and reject the mechanism that now ships.

Goal

constructor-rule-boundary.md states the scope its argument actually supports, names the constructor-chain mechanism as the case that escapes it, and cites the shipped Cell phase chain -- so no reader takes "sequencing is inexpressible at the type level" as unconditional.

Evidence: the claim and the argument it rests on

`Effect.gen` **is** the imperative shell -- `CONST-B1`'s shell as a value,
`CONST-B3`'s bread around the pure filling -- and sequencing is inexpressible
at the type level (see Why This Matters, (b)).

**(b) Why sequencing is not constructible.** The I/O sandwich -- read -> decode
-> decide -> shape -> write -- is an _ordering_ constraint, and an indexed
`Cell<Phase, A, E, R>` threaded through `Effect.gen` cannot express order.

Source: docs/solutions/architecture-patterns/constructor-rule-boundary.md:49,62 at 1574bfaa3c95d37c08475aff3806d5cf084c3dd0

The argument is sound for the mechanism it names -- Effect.gen unions its yielded effects, so order is lost. The headline sentence does not carry that restriction.

Orientation

The code cited here lands via branch feat/phase-order-as-description and is not on main yet. Every line reference is pinned to commit 1574bfaa3c95d37c08475aff3806d5cf084c3dd0; read it there.

  • The learning: docs/solutions/architecture-patterns/constructor-rule-boundary.md, headline at line 49, argument at section (b).
  • The mechanism that escapes it: packages/effect-cell-types/src/Cell.ts -- each phase constructor returns a stage type whose required member is a sentence, so composition order is checked by member presence rather than by threading one indexed value through Effect.gen. CONCEPTS.md's "Cell constructor" section already draws this distinction correctly and is the wording to align with.
  • The learning writes the sandwich as read -> decode -> decide -> shape -> write; the shipped vocabulary is encode, not shape. Reconcile the term while editing.
  • A second surface drifted the same way: packages/oxlint-plugins/effect-executor/AGENTS.md EE5 justifies leaving sandwich ordering to review because "the writing methods arrive through Context.Tag destructuring, so no import edge names their cell". Cell.write falsifies that premise -- inside a description the phases are named by import edge. EE5's check clause ("no rule in src/rules/ claims to enforce statement order") remains literally true and is not the problem; the rationale under it is.
  • docs/solutions/ is a Compound Engineering artifact directory. Amend the learning in place; do not delete it.

Non-Counting Outcomes

  • Deleting the learning, or the (b) argument. The negative result is still correct for Effect.gen-threaded values and is why the interpreter is shaped as it is; the defect is unstated scope, not wrongness.
  • Softening the headline to something unfalsifiable ("sequencing is hard to express") -- that removes the claim's usefulness instead of bounding it.
  • Editing the learning while leaving EE5's falsified rationale in place, so the next rule-author still reads a dead premise.
  • Recording the update as a new learning file that contradicts the old one without amending it, leaving two documents disagreeing about the same question.

Acceptance Criteria

  • constructor-rule-boundary.md states the mechanism its impossibility argument covers, and names the constructor-chain form as outside it, citing packages/effect-cell-types/src/Cell.ts.
  • No sentence in the file asserts unconditionally that ordering cannot be typed.
  • The shape / encode vocabulary mismatch with the shipped phases is resolved.
  • EE5's rationale in packages/oxlint-plugins/effect-executor/AGENTS.md no longer rests on "no import edge names their cell", and its check clause still describes what the rule fleet does.
  • pnpm check:local exits 0 after the last edit.

Metadata

Metadata

Assignees

No one assigned

    Labels

    documentationImprovements or additions to documentation

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions