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
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.mdstates the scope its argument actually supports, names the constructor-chain mechanism as the case that escapes it, and cites the shippedCellphase chain -- so no reader takes "sequencing is inexpressible at the type level" as unconditional.Evidence: the claim and the argument it rests on
Source:
docs/solutions/architecture-patterns/constructor-rule-boundary.md:49,62at1574bfaa3c95d37c08475aff3806d5cf084c3dd0The argument is sound for the mechanism it names --
Effect.genunions 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-descriptionand is not onmainyet. Every line reference is pinned to commit1574bfaa3c95d37c08475aff3806d5cf084c3dd0; read it there.docs/solutions/architecture-patterns/constructor-rule-boundary.md, headline at line 49, argument at section(b).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 throughEffect.gen.CONCEPTS.md's "Cell constructor" section already draws this distinction correctly and is the wording to align with.read -> decode -> decide -> shape -> write; the shipped vocabulary isencode, notshape. Reconcile the term while editing.packages/oxlint-plugins/effect-executor/AGENTS.mdEE5 justifies leaving sandwich ordering to review because "the writing methods arrive throughContext.Tagdestructuring, so no import edge names their cell".Cell.writefalsifies that premise -- inside a description the phases are named by import edge. EE5'scheckclause ("no rule insrc/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
(b)argument. The negative result is still correct forEffect.gen-threaded values and is why the interpreter is shaped as it is; the defect is unstated scope, not wrongness.Acceptance Criteria
constructor-rule-boundary.mdstates the mechanism its impossibility argument covers, and names the constructor-chain form as outside it, citingpackages/effect-cell-types/src/Cell.ts.shape/encodevocabulary mismatch with the shipped phases is resolved.packages/oxlint-plugins/effect-executor/AGENTS.mdno longer rests on "no import edge names their cell", and itscheckclause still describes what the rule fleet does.pnpm check:localexits 0 after the last edit.