CLAUDE/DESIGN/JOURNAL: design rationale ≠ implementation effort

User correction during the post-RC-overnight check-in: the 18a
"Type::Fn metadata vs. new Type variant" call was justified
across DESIGN.md, JOURNAL, and the commit message primarily by
"avoids ~250 match-arm sites". That is an observation about the
current state of the code, not a design rationale.

CLAUDE.md gains two binding rules:

- Design rationale ≠ implementation effort. Effort is at most a
  tiebreaker; a choice whose only stated reason is effort is
  suspect. The rule names the 18a misstep as the canonical
  anti-example so future sessions catch it earlier.
- Direction freedom + bounce-back conditions inlined (was
  previously a cross-reference to a private auto-memory file
  outside the repo, which the user couldn't see).

DESIGN.md Decision 10's Schema-additions block now leads with
the substantive reasons for per-position metadata: semantic
locality (modes belong to fn-parameter positions, not to types
in general — Decision 1 line); compositional clarity (type
identity vs. calling convention factor apart); future-proofing
(per-position metadata generalises; Type-variant approach
combinatoric blows up). The match-arm count remains parenthetical,
explicitly named a tiebreaker.

JOURNAL records the correction itself — the mistake stays as a
data point because how design discipline corrupts is informative.
This commit is contained in:
2026-05-08 09:29:33 +02:00
parent 3d22dc13bf
commit a91c3ffd94
3 changed files with 129 additions and 4 deletions
+43
View File
@@ -6098,3 +6098,46 @@ explicit modes) becomes the first program subject to the check;
its current shape (borrow-then-own on `xs`) is exactly what the
check should accept, so 18c.2 starts as a "green for the
existing test" iter.
## 2026-05-08 — Correction: 18a Schema-choice rationale
User flagged that the 18a "per-position metadata vs. `Type`
variants" decision was justified in the JOURNAL / DESIGN.md /
commit message primarily by implementation effort ("avoids
~250 match-arm sites"). That is not a design rationale. The
choice may still be right (it is), but the *reasons* it is
right have to come from the language, not from the cost of an
alternative. New CLAUDE.md section "Design rationale ≠
implementation effort" makes this a binding orchestrator rule.
The substantive justification, retroactively recorded in
`docs/DESIGN.md` Decision 10's Schema-additions block:
1. **Semantic locality.** Modes are properties of fn-signature
parameter positions, not of types in general. Embedding modes
in `Type` would let the schema permit forms like
`(con List (borrow Int))` — syntactically possible but
semantically meaningless. Decision 1's "schema permits
exactly what is meaningful" argues against the Type-variant
approach.
2. **Compositional clarity.** A `Type` value's identity should
depend only on the type. Calling-convention information
(own/borrow) is orthogonal to type identity; mixing them
conflates two axes that should be factored apart.
3. **Future-proof against more position metadata.** Per-position
metadata generalises naturally to additional dimensions
(streaming, captured, lifetime witness). The Type-variant
approach would force every new dimension into its own
`Type::*` variant and produce combinatoric ordering questions
(`Borrow(Streamed(T))` vs `Streamed(Borrow(T))`) that don't
arise when modes live in a flat metadata vector.
The match-arm count remains true as an observation but appears
in DESIGN.md only parenthetically, marked explicitly as a
tiebreaker rather than a rationale.
This entry stays as a record because the original mistake is
informative — design discipline corrupts faster than I notice
when I let "implementer-friendly" creep into the slot reserved
for "language-honest". The CLAUDE.md rule exists so the next
session catches this earlier.