@@ -491,3 +491,181 @@ references = [
491491 "lib/lexer.ml (ZERO/ONE never emitted)",
492492 "lib/parser.mly quantity rule (lines 180-183)",
493493]
494+
495+ [[adr]]
496+ id = "ADR-008"
497+ status = "accepted"
498+ date = "2026-04-11"
499+ title = "Effect invocation uses direct call syntax — no 'perform' keyword"
500+ context = """
501+ Algebraic effects require a syntax for invoking an effect operation at a
502+ call site. Two candidates exist in the literature:
503+
504+ 1. Direct call: `Http.get(url)` — the effect operation looks like a
505+ namespaced function call. The effect is declared in the return type
506+ annotation (`-> T / Http, Async`) not at each call site.
507+
508+ 2. Explicit perform: `perform Http.get(url)` — the keyword makes the
509+ effectful nature of the call visible at every use site. Used by Koka
510+ (earlier versions) and some effect-system research languages.
511+
512+ The AffineScript DESIGN-VISION.adoc already shows direct call style in its
513+ effect examples. The decision needed to be made explicit so the conformance
514+ suite, parser, and documentation are unambiguous.
515+ """
516+ decision = """
517+ Effect operations are invoked with direct call syntax. No `perform` keyword.
518+
519+ fn fetch_user(id: Int) -> User / Http, Async {
520+ let resp = Http.get("/users/" ++ show(id))
521+ Async.await(resp.json())
522+ }
523+
524+ The effect is declared once — in the return type annotation (`/ Http, Async`).
525+ The call sites are plain calls. The type signature is the contract; the call
526+ site is just a call.
527+ """
528+ consequences = """
529+ - The conformance suite, parser, and spec must not admit or require `perform`.
530+ - Effect operation calls are syntactically indistinguishable from regular
531+ function calls; the distinction is entirely in the type system.
532+ - Error messages for unhandled effects reference the return type annotation,
533+ not a `perform` site.
534+ - This is consistent with the ergonomics goal: effect-heavy code does not
535+ accumulate keyword noise at every call site.
536+ - Face parsers (Python-face, JS-face) can map `async/await` to the Async
537+ effect without introducing a `perform` concept — `await` desugars to
538+ `Async.await(...)`, which is a direct call.
539+ """
540+ references = [
541+ "docs/DESIGN-VISION.adoc (effect examples)",
542+ "docs/specs/effects.md",
543+ ]
544+
545+ [[adr]]
546+ id = "ADR-009"
547+ status = "accepted"
548+ date = "2026-04-11"
549+ title = "The conformance suite is authoritative — parser must conform to spec"
550+ context = """
551+ The conformance suite (test/conformance/) contains valid AffineScript programs
552+ drawn from the spec. As of 2026-04-11, 8 of 12 valid conformance tests fail
553+ to parse. The three categories of failure are:
554+
555+ 1. Uppercase type names — `Int`, `String`, `Bool`, `Option` are written in
556+ the spec with PascalCase. The parser's `ident` rule accepts only lowercase,
557+ so `Int` fails to parse as a type name.
558+
559+ 2. ML-style enum syntax — the spec's enum declaration syntax does not match
560+ what the parser accepts.
561+
562+ 3. Effect op type parameters — the spec includes type parameters on effect
563+ operations; the parser does not support them.
564+
565+ Two possible authorities: the spec (conformance suite) or the parser
566+ (current implementation).
567+ """
568+ decision = """
569+ The spec is authoritative. The parser must conform to the spec. This is
570+ consistent with the standing estate-wide rule: 'Language scope lives in a
571+ written thesis. Thesis authoritative, code must conform. If disagreement,
572+ code is wrong.'
573+
574+ Specific required changes:
575+ 1. Parser must accept PascalCase type names (`Int`, `String`, `Bool`, user-
576+ defined types). The type name namespace is PascalCase; value names remain
577+ camelCase/snake_case. This also fixes the conformance suite failure where
578+ effect and enum type names could not be written.
579+ 2. Parser must accept the spec's enum declaration syntax (to be confirmed
580+ against spec and fixed accordingly).
581+ 3. Parser must support type parameters on effect operations.
582+
583+ The target is 12/12 conformance suite passing.
584+ """
585+ consequences = """
586+ - lib/lexer.ml and lib/parser.mly are updated to accept PascalCase type names.
587+ - The `ident` vs `type_ident` distinction is formalised in the grammar:
588+ `ident` = lowercase-leading (values, variables, functions)
589+ `type_ident` = uppercase-leading (types, effects, enums, type aliases)
590+ - lib/parser.mly enum and effect rules are audited against spec and fixed.
591+ - 12/12 conformance tests pass. The conformance suite becomes a live
592+ regression suite — any future parser change that breaks a conformance test
593+ is a bug, not a spec disagreement.
594+ - All fixture files under test/e2e/fixtures/ that use lowercase type names
595+ (e.g. `type point = ...`) are reviewed; lowercase type aliases remain valid
596+ (they are value-level names) but builtin types (`int` written lowercase)
597+ are normalised to PascalCase.
598+ - Error messages and diagnostics use PascalCase type names consistently.
599+ """
600+ references = [
601+ "test/conformance/",
602+ "lib/lexer.ml",
603+ "lib/parser.mly",
604+ "docs/spec.md",
605+ ]
606+
607+ [[adr]]
608+ id = "ADR-010"
609+ status = "accepted"
610+ date = "2026-04-11"
611+ title = "Face-aware error formatting is a first-class toolchain concern"
612+ context = """
613+ AffineScript supports syntactic face layers (Python-face, JS-face,
614+ pseudocode-face, canonical AffineScript) that allow developers to write
615+ AffineScript using familiar surface syntax from other languages. The compiler
616+ pipeline forks only at the parser; everything downstream (type checker,
617+ codegen) is shared and operates on the canonical AST.
618+
619+ Without face-aware error formatting, a developer writing Python-face
620+ AffineScript receives type errors expressed in canonical AffineScript
621+ syntax — terms and constructs they have deliberately not learned yet. This
622+ shatters the face illusion at the worst possible moment (when the developer
623+ is stuck and needs help) and is a direct contradiction of the adoption goal.
624+ """
625+ decision = """
626+ Face-aware error formatting is a first-class toolchain concern, not an
627+ afterthought. It is implemented as a formatting layer between the compiler
628+ and the terminal, not inside the compiler itself.
629+
630+ Architecture:
631+ compiler (emits errors in canonical AST terms)
632+ ↓
633+ face-aware error formatter ← separate concern, swappable
634+ ↓
635+ terminal / IDE / LSP
636+
637+ The compiler's error representation is canonical and face-agnostic. The
638+ formatter receives: (error, active-face) → formatted error string.
639+
640+ Each face provides an error vocabulary mapping:
641+ canonical term → face term
642+ e.g. (python-face) "affine binding" → "single-use variable"
643+ e.g. (js-face) "Option[T]" → "T | null" [with note: 'use .unwrap_or()']
644+
645+ Error source spans are always reported in the face's syntax, not canonical
646+ AffineScript syntax, since the user's file is written in the face.
647+ """
648+ consequences = """
649+ - The compiler's error types carry enough information for the formatter to
650+ reconstruct face-appropriate messages. No compiler internals leak face
651+ knowledge.
652+ - Each face ships with an error vocabulary file (part of the face definition).
653+ - The toolchain (CLI, LSP server, playground) passes the active face to the
654+ formatter. The formatter is the single point of face-awareness for errors.
655+ - A developer on Python-face who hits a linearity violation sees:
656+ Error: single-use variable 'x' used twice
657+ → line 7, in greet
658+ not:
659+ Error: affine binding 'x' used 2 times (quantity violation: QOne, found 2)
660+ - The face formatter is versioned alongside the face. When a face is
661+ deprecated, its error formatter is deprecated with it.
662+ - The IDE/LSP integration carries face information in the project config so
663+ hover types, completions, and inline errors all speak the face's vocabulary.
664+ - This is a design commitment, not an immediate implementation task. The
665+ canonical compiler error representation must be designed with this
666+ formatability requirement in mind from the start.
667+ """
668+ references = [
669+ "docs/DESIGN-VISION.adoc (faces section)",
670+ "docs/specs/faces.md (to be written)",
671+ ]
0 commit comments