{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "version": "1.0.0",
  "lastUpdated": "2026-01-27",
  "description": "Structured reference for AI coding assistants working with EK9",
  "documentation": "https://ek9.io/forAI.html",

  "excludedFeatures": {
    "description": "Features deliberately excluded from EK9 based on production bug evidence",
    "features": [
      {
        "keyword": "break",
        "errorCode": "E01070",
        "errorUrl": "https://ek9.io/errors.html#E01070",
        "reason": "15% of C# bugs (Microsoft 2011), 200+ Linux kernel CVEs",
        "alternative": "Stream pipelines with 'head' or guards",
        "example": {
          "wrong": "for item in items\n  if isMatch(item)\n    break",
          "correct": "result <- cat items | filter by isMatch | head 1 | collect as List of String"
        },
        "documentation": "https://ek9.io/flowControl.html#streams"
      },
      {
        "keyword": "continue",
        "errorCode": "E01071",
        "errorUrl": "https://ek9.io/errors.html#E01071",
        "reason": "15% of C# bugs (Microsoft 2011), 3x higher defect density",
        "alternative": "Stream pipelines with 'filter' or 'reject'",
        "example": {
          "wrong": "for item in items\n  if not isValid(item)\n    continue\n  process(item)",
          "correct": "valid <- cat items | filter by isValid | collect as List of String\nfor item in valid\n  process(item)"
        },
        "documentation": "https://ek9.io/flowControl.html#streams"
      },
      {
        "keyword": "return",
        "errorCode": "E01072",
        "errorUrl": "https://ek9.io/errors.html#E01072",
        "reason": "Apple SSL bug (2014), 23% of resource leaks (Google study)",
        "alternative": "Return declarations with '<-' and declaration guards",
        "example": {
          "wrong": "process()\n  -> content as String\n  <- result as String?\n  if not content?\n    return \"\"",
          "correct": "process()\n  -> content as String\n  <- result as String: String()\n  if content?\n    result: transform(content)"
        },
        "documentation": "https://ek9.io/flowControl.html#guards"
      },
      {
        "keyword": "null",
        "errorCode": "E01073",
        "errorUrl": "https://ek9.io/errors.html#E01073",
        "reason": "Billion-dollar mistake (Hoare), #1 Java exception",
        "alternative": "Tri-state semantics (absent/unset/set) with '?' operator",
        "example": {
          "wrong": "name <- null",
          "correct": "name <- String()  // Creates UNSET String\nif name?\n  process(name)  // Safe - guaranteed set"
        },
        "documentation": "https://ek9.io/basics.html#tri-state"
      },
      {
        "keyword": ";",
        "name": "semicolon",
        "errorCode": "E01074",
        "errorUrl": "https://ek9.io/errors.html#E01074",
        "reason": "Indentation-based syntax (like Python)",
        "alternative": "Simply remove - EK9 uses newlines and indentation",
        "example": {
          "wrong": "name <- \"Steve\";",
          "correct": "name <- \"Steve\""
        },
        "documentation": "https://ek9.io/structure.html#indentation"
      },
      {
        "keyword": "new",
        "errorCode": "E01075",
        "errorUrl": "https://ek9.io/errors.html#E01075",
        "reason": "EK9 uses TypeName() directly without 'new' keyword",
        "alternative": "Call type constructor directly: Person() instead of new Person()",
        "example": {
          "wrong": "person <- new Person(\"Steve\")",
          "correct": "person <- Person(\"Steve\")"
        },
        "documentation": "https://ek9.io/basics.html#construction"
      },
      {
        "keyword": "goto",
        "errorCode": "E01076",
        "errorUrl": "https://ek9.io/errors.html#E01076",
        "reason": "Dijkstra (1968) 'Go To Statement Considered Harmful', Apple SSL bug (2014)",
        "alternative": "Use structured control flow: try/finally, guards",
        "example": {
          "wrong": "if error\n  goto cleanup",
          "correct": "try\n  riskyOperation()\nfinally\n  cleanup()"
        },
        "documentation": "https://ek9.io/flowControl.html#structured"
      },
      {
        "keyword": "def",
        "errorCode": "E01077",
        "errorUrl": "https://ek9.io/errors.html#E01077",
        "reason": "EK9 defines functions by name directly without keyword (Python syntax excluded)",
        "note": "Written where a function is declared, 'def greet(name as String)' is a plain syntax error; E01077 is reported where 'def name()' appears as a statement",
        "alternative": "Start with function name directly, use -> for parameters, <- for returns",
        "example": {
          "wrong": "def greet(name as String)\n  stdout.println(\"Hello \" + name)",
          "correct": "greet()\n  -> name as String\n  stdout <- Stdout()\n  stdout.println(\"Hello \" + name)"
        },
        "documentation": "https://ek9.io/functions.html"
      },
      {
        "keyword": "elif",
        "errorCode": "E01078",
        "errorUrl": "https://ek9.io/errors.html#E01078",
        "reason": "EK9 uses 'else if' as two words for readability (Python syntax excluded)",
        "alternative": "Use 'else if' (two separate words)",
        "example": {
          "wrong": "if x > high\n  big()\nelif x > low\n  medium()",
          "correct": "if x > high\n  big()\nelse if x > low\n  medium()"
        },
        "documentation": "https://ek9.io/flowControl.html#if"
      },
      {
        "keyword": "None",
        "errorCode": "E01079",
        "errorUrl": "https://ek9.io/errors.html#E01079",
        "reason": "Python's None equivalent - EK9 uses tri-state semantics instead",
        "alternative": "Use TypeName() for unset values, '?' operator to check if set",
        "example": {
          "wrong": "name <- None",
          "correct": "name <- String()  // Creates UNSET String\nif name?\n  process(name)"
        },
        "documentation": "https://ek9.io/basics.html#tri-state"
      },
      {
        "keyword": "self",
        "errorCode": "E01080",
        "errorUrl": "https://ek9.io/errors.html#E01080",
        "reason": "EK9 uses 'this' instead of 'self' (Java/C++/JavaScript convention)",
        "alternative": "Use 'this' keyword, or omit when unambiguous",
        "example": {
          "wrong": "greet()\n  stdout <- Stdout()\n  stdout.println(\"I am \" + self.name)",
          "correct": "greet()\n  stdout <- Stdout()\n  stdout.println(\"I am \" + this.name)\n  // Or simply: \"I am \" + name"
        },
        "documentation": "https://ek9.io/classes.html#this"
      },
      {
        "keyword": "close",
        "errorCode": "E01094",
        "errorUrl": "https://ek9.io/errors.html#E01094",
        "reason": "Every close is generated, so a hand-written close could only close a value twice or under an owner still using it (double close, use after close)",
        "alternative": "A local is a try-with-resources resource (or stays unnamed, and its statement closes it); a type's own closeable properties are closed by 'default operator close' or the chain after a written 'operator close'. 'x.close()' is E81060.",
        "example": {
          "wrong": "operator close as pure\n  close conn",
          "correct": "default operator close  // closes conn, then the super class's close"
        },
        "documentation": "https://ek9.io/errors.html#E01094"
      },
      {
        "keyword": "listComprehension",
        "name": "Python list comprehension",
        "pattern": "[x for x in items]",
        "errorCode": "E01081",
        "errorUrl": "https://ek9.io/errors.html#E01081",
        "reason": "EK9 uses stream pipelines for composability and lazy evaluation",
        "alternative": "Define function for transformation, use 'cat collection | map with fn | collect as List' pattern",
        "example": {
          "wrong": "squares <- [x * x for x in numbers]",
          "correct": "defines function\n  squareIt() as pure\n    -> n as Integer\n    <- result as Integer: n * n\n\ndefines program\n  Squares()\n    numbers <- [1, 2, 3]\n    squares <- cat numbers | map with squareIt | collect as List of Integer\n    Stdout().println($squares)"
        },
        "documentation": "https://ek9.io/streamsAndPipelines.html"
      },
      {
        "keyword": "multipleArgumentArrows",
        "name": "multiple '->' arrows for parameters",
        "pattern": "-> param1 as T1\n-> param2 as T2",
        "errorCode": "E01082",
        "errorUrl": "https://ek9.io/errors.html#E01082",
        "reason": "EK9 uses ONE '->' with indented block for multiple parameters",
        "alternative": "Use single '->' followed by indented parameter block",
        "example": {
          "wrong": "badFunction()\n  -> param1 as String\n  -> param2 as Integer\n  <- result as String: `${param1} ${param2}`",
          "correct": "goodFunction()\n  ->\n    param1 as String\n    param2 as Integer\n  <- result as String: `${param1} ${param2}`"
        },
        "documentation": "https://ek9.io/functions.html#parameters"
      },
      {
        "keyword": "multipleReturnArrows",
        "name": "multiple '<-' arrows for returns",
        "pattern": "<- result1 as T1\n<- result2 as T2",
        "errorCode": "E01083",
        "errorUrl": "https://ek9.io/errors.html#E01083",
        "reason": "EK9 functions have exactly ONE return declaration - use records for multiple values",
        "alternative": "Create a record type and return a single instance containing multiple fields",
        "example": {
          "wrong": "badFunction()\n  -> input as String\n  <- result1 as String: input\n  <- result2 as Integer: length input",
          "correct": "defines record\n  ReturnValues\n    text as String: String()\n    count as Integer: Integer()\n\n    ReturnValues()\n      ->\n        text as String\n        count as Integer\n      this.text: text\n      this.count: count\n\n    default operator\n\ndefines function\n  goodFunction()\n    -> input as String\n    <- rtn as ReturnValues: ReturnValues(input, length input)"
        },
        "documentation": "https://ek9.io/functions.html#returns"
      },
      {
        "keyword": "instanceof",
        "name": "type checking",
        "reason": "Breaks polymorphism, creates brittle code, causes maintenance bugs",
        "alternative": "Use 'dispatcher' methods for type-specific behavior",
        "note": "There is NO way to check types at runtime in EK9 - this is by design",
        "documentation": "https://ek9.io/advancedClassMethods.html#dispatcher"
      },
      {
        "keyword": "casting",
        "name": "type casting",
        "reason": "Breaks type safety, enables ClassCastException-style bugs",
        "alternative": "Use 'dispatcher' methods - compiler routes to correct overload",
        "note": "There is NO way to cast types in EK9 - this is by design",
        "documentation": "https://ek9.io/advancedClassMethods.html#dispatcher"
      },
      {
        "keyword": "const",
        "name": "constant data modifier",
        "reason": "EK9 takes a fundamentally different approach: the constraint is on the OPERATION, not the data",
        "alternative": "Mark functions/methods 'as pure' — compiler prevents all mutation in pure contexts at compile time",
        "note": "Data is NEVER const in EK9. Immutability is contextual: the same List is unmutatable in a pure function but fully mutable in a non-pure function. This preserves the Liskov Substitution Principle — Java's immutable collections break LSP by throwing runtime UnsupportedOperationException",
        "documentation": "https://ek9.io/basics.html#pure"
      },
      {
        "keyword": "final",
        "name": "final/sealed modifier",
        "reason": "EK9 types are CLOSED by default (no 'final' needed). For data immutability, use 'as pure' on operations",
        "alternative": "Types are closed by default — use 'as open' to allow extension. Use 'as pure' for mutation control",
        "note": "Two concepts combined in other languages: (1) Extension prevention — EK9 types are closed by default, use 'as open' to opt in. (2) Data immutability — use 'as pure' on functions/methods, not 'final' on data",
        "documentation": "https://ek9.io/classes.html"
      },
      {
        "keyword": "immutable",
        "name": "immutable data types",
        "reason": "EK9 has NO immutable List, Dict, record, or any data type — and never will. ALL types are mutable",
        "alternative": "Mark functions/methods 'as pure' — compiler prevents mutation at compile time, not runtime",
        "note": "Java's immutable List breaks the Liskov Substitution Principle by throwing UnsupportedOperationException at runtime. EK9 prevents mutation at COMPILE TIME instead. The same object can be: unmutatable when passed to a pure function, fully mutable when passed to a non-pure function. Immutability is contextual, not permanent",
        "documentation": "https://ek9.io/basics.html#pure"
      },
      {
        "keyword": "classBraces",
        "name": "Java/C# class definition with braces and access modifiers",
        "reason": "EK9 class definitions use INDENTATION (like Python), not braces. Fields are ALWAYS private (no access modifier keyword). Methods do NOT use 'public', 'private', 'protected', 'void', or 'this.' prefix. Method signatures use '-> input as Type' for parameters and '<- result as Type' for return values. NO 'new Type()' for construction — just 'Type()'.",
        "alternative": "Use indentation-based EK9 class syntax. Fields declared bare. Constructor name matches class name. Methods use '-> input as Type' / '<- result as Type'. Field access without 'this.' prefix.",
        "example": {
          "wrong": "defines class UniqueNames {\n  private List<String> names = new List<String>();\n  public void add(String name) {\n    if (!names.contains(name)) {\n      names.add(name);\n    }\n  }\n  public int count() {\n    return names.size();\n  }\n}",
          "correct": "defines class\n  UniqueNames\n    names as List of String?\n\n    UniqueNames()\n      names: List() of String\n\n    add()\n      -> name as String\n      if not name in names\n        names += name\n\n    count() as pure\n      <- rtn as Integer: names.length()\n\n    default operator ?"
        },
        "rule": "EK9 has NO { } braces, NO 'public/private/protected', NO 'void', NO 'this.', NO 'new'. Indentation is the structure. Fields are bare names. Constructor identical to class name. '-> ' for params, '<- ' for return.",
        "documentation": "https://ek9.io/structure.html#class"
      },
      {
        "keyword": "switchCStyle",
        "name": "C/Java switch with parens, braces, colons, and return statements",
        "reason": "EK9 switch uses indentation (no braces), no parens around argument, no colons after case labels. Switch CAN BE an expression — its result assigned to a variable. Multiple values per case via comma: 'case 1, 2, 3'. NO 'return' statement — assign to declared return variable: 'rtn: value'. NO fall-through (each case is independent by design).",
        "alternative": "Use the EK9 indentation-based switch with bare 'case x' (no colon). Body of each case indents. Assign result to a variable for switch-as-expression, or assign to outer return variable for switch-as-statement.",
        "example": {
          "wrong": "function findLabel(code: Integer): String {\n  switch(code) {\n    case 1: return \"active\";\n    case 2: return \"inactive\";\n    default: return \"unknown\";\n  }\n}",
          "correct": "findLabel() as pure\n  -> code as Integer\n  <- rtn as String?\n  switch code\n    case 1\n      rtn: \"active\"\n    case 2\n      rtn: \"inactive\"\n    default\n      rtn: \"unknown\""
        },
        "rule": "EK9 switch: NO parens around argument, NO braces, NO colons after case/default labels, NO 'return' statement. Body of each case indents under bare 'case x'. Switch can be an expression: 'result <- switch x' with new variable, or assign in each case to an outer return variable.",
        "documentation": "https://ek9.io/flowControl.html#switch"
      },
      {
        "keyword": "lowercasePrimitives",
        "name": "Java/C# lowercase primitive type names",
        "reason": "EK9 primitive types are PascalCase: Integer, String, Boolean, Float, Date, Money. There are NO 'int', 'string', 'bool', 'float' lowercase primitives. EK9 wraps these as proper objects with built-in operators (==, <=>, $, #?, ?, etc.) and tri-state semantics (absent/unset/set).",
        "alternative": "Use PascalCase EK9 type names: Integer not int, String not string, Boolean not bool, Float not float. These are full objects with operator support, not primitive values.",
        "example": {
          "wrong": "function add(a: int, b: int): int {\n  return a + b;\n}",
          "correct": "add() as pure\n  ->\n    a as Integer\n    b as Integer\n  <- rtn as Integer: a + b"
        },
        "rule": "EK9 primitive type names are PascalCase (Integer, String, Boolean, Float, Date). Lowercase 'int'/'string'/'bool'/'float' do NOT exist. The PascalCase types are full objects with built-in operators and tri-state semantics.",
        "documentation": "https://ek9.io/standardTypes.html"
      }
    ]
  },

  "dispatcherPattern": {
    "description": "EK9's replacement for instanceof/casting - the ONLY way to handle type-specific behavior",
    "criticalRule": "There is NO instanceof and NO casting in EK9. Dispatcher is the ONLY mechanism.",
    "howItWorks": "Mark a method 'as dispatcher', provide overloaded methods for specific types, compiler generates dispatch logic",
    "whyMethodsOnly": "Functions cannot be overloaded (names must be unique in module), so dispatcher only works on methods",
    "singleDispatch": {
      "description": "Dispatch on one parameter's runtime type",
      "example": "render() as dispatcher\n  -> shape as Shape\n  shape.draw()\n\nrender()\n  -> circle as Circle\n  Stdout().println(`Circle of radius ${circle.radius()}`)"
    },
    "doubleDispatch": {
      "description": "Dispatch on two parameters' runtime types (visitor pattern replacement)",
      "example": "intersect() as dispatcher\n  ->\n    s1 as Shape\n    s2 as Shape\n  <- result as Intersection: NoIntersection()\n\nintersect()\n  ->\n    s1 as Circle\n    s2 as Circle\n  <- result as Intersection: ArcIntersection()"
    },
    "ambiguityDetection": {
      "description": "Compiler detects ambiguous dispatch and requires explicit resolution",
      "example": "If Square implements T1 and T2, and you have render(T1) and render(T2), compiler requires render(Square) to disambiguate"
    },
    "fallbackBehavior": "If no specific type match exists, the dispatcher's own implementation is called as default",
    "relatedErrors": ["E07120", "E07820", "E05170", "E05180"],
    "documentation": "https://ek9.io/advancedClassMethods.html#dispatcher"
  },

  "triStateSemantics": {
    "description": "EK9's tri-state object model replaces null",
    "states": [
      {
        "name": "absent",
        "meaning": "Object doesn't exist",
        "example": "Dict key not found"
      },
      {
        "name": "unset",
        "meaning": "Object exists but has no meaningful value",
        "example": "String() creates unset String"
      },
      {
        "name": "set",
        "meaning": "Object exists with valid, usable value",
        "example": "String(\"hello\") is set"
      }
    ],
    "criticalRule": "Collections (List, Dict) are ALWAYS set when created, even if empty. Only primitives (String, Integer) are unset when empty.",
    "operator": "?",
    "operatorMeaning": "Calls _isSet() method to check if value is set",
    "documentation": "https://ek9.io/basics.html#tri-state"
  },

  "closedByDefault": {
    "description": "EK9 types are closed by default (like Kotlin)",
    "errorCode": "E05030",
    "errorUrl": "https://ek9.io/errors.html#E05030",
    "neverExtendable": ["List", "Dict", "DictEntry", "MutexLock", "Optional", "PriorityQueue", "Result"],
    "howToMakeExtendable": "Declare with 'as open' modifier",
    "correctPattern": "Use composition/delegation instead of inheritance",
    "example": {
      "wrong": "MyList extends List of String",
      "correct": "MyList\n  items as List of String: List() of String\n\n  add()\n    -> item as String\n    items += item\n\n  default operator ?"
    },
    "documentation": "https://ek9.io/inheritance.html#closed-by-default"
  },

  "accessModifiers": {
    "description": "EK9 access modifier rules vary by declaration kind - fields, methods, and operators each have different rules",
    "criticalRule": "Fields are ALWAYS private in classes/components (no syntax to change this). Only METHODS support public/protected/private modifiers.",
    "fields": {
      "rule": "Fields (properties) have NO access modifier in the grammar",
      "classFields": "Always private - subclasses cannot access parent fields directly",
      "recordFields": "Always public - records are data structures with public access",
      "componentFields": "Always private - same as class fields",
      "traitFields": "Traits cannot have fields",
      "packageProperties": "Always public within module scope",
      "noProtectedFields": "There is no way to declare a protected field - this is deliberate to avoid the fragile base class problem",
      "subclassAccess": "Use accessor methods (public or protected) to expose parent state to subclasses"
    },
    "methods": {
      "rule": "Methods support optional access modifiers",
      "syntax": "(OVERRIDE | DEFAULT)? accessModifier? identifier ...",
      "defaultAccess": "Public (no modifier needed)",
      "options": ["public", "protected", "private"],
      "protectedMethods": "Accessible from subclasses and same-hierarchy types",
      "privateMethods": "Accessible only within the declaring type"
    },
    "operators": {
      "rule": "Operators have NO access modifier - always public",
      "syntax": "(OVERRIDE | DEFAULT)? OPERATOR operator ...",
      "rationale": "Operators define the public contract of a type"
    },
    "example": {
      "wrong": "defines class\n  MyClass as open\n    protected name <- String()    //WRONG: grammar error, fields cannot have access modifiers",
      "correct": "defines class\n  MyClass as open\n    name <- String()              //Field is always private\n\n    protected getName() as pure   //Use protected method for subclass access\n      <- rtn as String: name\n\n    default operator ?\n\n  ChildClass extends MyClass\n    describe()\n      <- rtn as String: getName() //Access parent state via method"
    },
    "errorCodes": {
      "E06180": "Field or method not accessible from this context (private access violation)"
    },
    "documentation": "https://ek9.io/advancedClassMethods.html"
  },

  "assignmentOperators": {
    "description": "Three distinct assignment operators with precise semantics",
    "operators": [
      {
        "operator": "<-",
        "name": "Declaration",
        "semantics": "Create NEW variable + first assignment",
        "useCase": "First-time assignment"
      },
      {
        "operator": ":=",
        "name": "Assignment",
        "semantics": "Assign to EXISTING variable",
        "useCase": "Reassignment"
      },
      {
        "operator": ":=?",
        "name": "Assign-If-Unset",
        "semantics": "Fill the variable only if it is UNSET; the right side is not evaluated otherwise (a :=? b is a := a ?: b). It always leaves an object in the target - present, maybe unset, never absent - so it initialises a variable declared with no value where it always runs",
        "useCase": "Conditional initialization, defaults"
      }
    ],
    "names": "One name per symbol: x? = set-check; <- = declaration (in a control-flow head: declaration guard); := = assignment (blind in a head - add then x?); :=? = assign-if-unset; ?: = coalesce (Elvis); <? <=? >? >=? = comparison coalescing (returns an operand); guard = enter only if set (Swift's if let). There is no ?= operator and no assignment yields a value",
    "documentation": "https://ek9.io/basics.html#assignments"
  },

  "guardExpressions": {
    "description": "Guards combine assignment with null/isSet checking. The part of a control-flow head before then/with is the pre-flow: it runs exactly once, before the body (a while/do-while re-tests only its condition)",
    "syntax": "if variable <- expression",
    "meaning": "Execute block only if expression result is SET",
    "worksIn": ["if", "switch", "for", "while", "do", "try"],
    "operators": [
      {"operator": "<-", "inHead": "declare a NEW variable, enter only if it is SET", "example": "if name <- getName()"},
      {"operator": ":= then x?", "inHead": "re-point an EXISTING variable (an unset result overwrites it), then the explicit check enters only if it is now SET; parenthesise any further condition", "example": "if name := getName() then name? and (name <> \"guest\")"},
      {"operator": ":=?", "inHead": "assign only if the variable is UNSET (the right side is not even evaluated otherwise), enter if it is SET afterwards", "example": "if cache :=? compute()"},
      {"operator": ":=", "inHead": "blind assignment, no set-check: an if needs its own condition (E07340)", "example": "if count := getCount() then count > 0"}
    ],
    "booleanTruthGuard": "In an if / else if, a <- or :=? head whose variable is declared exactly Boolean enters only when it is SET AND TRUE (if allowed <- permitted(user) skips false as well as unset). switch keeps enter-if-set so case false stays reachable; while, do, for and try too",
    "laterElseBlocks": "Every later else if / else of an if chain runs because a <- guard failed, so reading that guard's variable there before assigning it is E08270",
    "switchForTryDo": "These have no then x? gate: assign first, then wrap the construct - x := f() then if x? around switch x - or use <- when the variable is only needed inside",
    "asExpression": "An assignment never yields a value: write x := f() then ok <- x? to know whether the new value is set. To keep x when f() is unset write x := f() ?: x (?? passes an unset value through). Rejected: x :=? on an always-set x (E08095), a := head with no condition (E07340 - write if x := f() then x?)",
    "examples": [
      {
        "construct": "if",
        "code": "if name <- getName()\n  stdout.println(name)"
      },
      {
        "construct": "for",
        "code": "for config <- getConfig() then item in items\n  process(config, item)"
      },
      {
        "construct": "while",
        "code": "while conn <- getActiveConnection() then conn.hasMore()\n  transferData(conn)"
      }
    ],
    "documentation": "https://ek9.io/flowControl.html#guards"
  },

  "qualityMetrics": {
    "description": "Compile-time enforced quality thresholds",
    "metrics": [
      {
        "name": "Cyclomatic Complexity",
        "abbreviation": "CC",
        "good": "<=10",
        "monitor": "11-15",
        "warning": "16-25",
        "limit": 45,
        "errorCode": "E11010",
        "errorUrl": "https://ek9.io/errors.html#E11010"
      },
      {
        "name": "Cognitive Complexity",
        "abbreviation": "Cog",
        "good": "<=10",
        "monitor": "11-15",
        "warning": "16-25",
        "limit": 35,
        "errorCode": "E11021",
        "errorUrl": "https://ek9.io/errors.html#E11021"
      },
      {
        "name": "Nesting Depth",
        "good": "<=2",
        "monitor": "3",
        "warning": "4-5",
        "limit": 6,
        "errorCode": "E11011",
        "errorUrl": "https://ek9.io/errors.html#E11011"
      },
      {
        "name": "Bracket Nesting",
        "description": "'(', '[' and '{' together, checked as the source is read - before it is parsed",
        "good": "<=3",
        "monitor": "4-6",
        "warning": "7-10",
        "limit": 10,
        "errorCode": "E11011",
        "errorUrl": "https://ek9.io/errors.html#E11011"
      },
      {
        "name": "Block Nesting",
        "description": "Indentation levels from the module down, checked as the source is read - before it is parsed",
        "good": "<=12",
        "monitor": "13-16",
        "warning": "17-20",
        "limit": 20,
        "errorCode": "E11011",
        "errorUrl": "https://ek9.io/errors.html#E11011"
      },
      {
        "name": "Operators per Expression",
        "description": "One expression ends at a comma or at the end of its statement; checked before parsing. Coalescing chains are held to 3 (2 for <? >? <=? >=?) by expression complexity",
        "good": "<=7",
        "monitor": "8-14",
        "warning": "15-20",
        "limit": 20,
        "errorCode": "E11013",
        "errorUrl": "https://ek9.io/errors.html#E11013"
      },
      {
        "name": "Member Accesses per Expression",
        "description": "'.' in one expression, as in a.b().c(); checked before parsing. A module's dotted name is not counted",
        "good": "<=3",
        "monitor": "4-7",
        "warning": "8-20",
        "limit": 20,
        "errorCode": "E11013",
        "errorUrl": "https://ek9.io/errors.html#E11013"
      },
      {
        "name": "Statement Count",
        "good": "<=50",
        "monitor": "51-100",
        "warning": "101-150",
        "limit": 150,
        "errorCode": "E11012",
        "errorUrl": "https://ek9.io/errors.html#E11012"
      },
      {
        "name": "Cohesion (LCOM4)",
        "good": "<=3",
        "monitor": "4-5",
        "warning": "6-8",
        "limit": 8,
        "errorCode": "E11014",
        "errorUrl": "https://ek9.io/errors.html#E11014"
      },
      {
        "name": "Coupling (Ce)",
        "good": "<=5",
        "monitor": "6-8",
        "warning": "9-12",
        "limit": 12,
        "errorCode": "E11015",
        "errorUrl": "https://ek9.io/errors.html#E11015"
      },
      {
        "name": "Inheritance Depth",
        "good": "<=2",
        "monitor": "3",
        "warning": "4",
        "limit": 4,
        "errorCode": "E11019",
        "errorUrl": "https://ek9.io/errors.html#E11019"
      },
      {
        "name": "Coverage",
        "good": ">=80%",
        "monitor": "60-79%",
        "warning": "<60%",
        "limit": "80% for publishing"
      }
    ],
    "documentation": "https://ek9.io/quality.html"
  },

  "bannedIdentifiers": {
    "description": "Variable names E11031 rejects (case-insensitive) - rendered at build time from the compiler's NonDescriptiveNames, the single source; never hand-edit this array.",
    "banned": [
      {"name": "temp", "defectMultiplier": 3.1},
      {"name": "tmp", "defectMultiplier": 3.1},
      {"name": "flag", "defectMultiplier": 3.4},
      {"name": "flg", "defectMultiplier": 3.4},
      {"name": "data", "defectMultiplier": 2.8},
      {"name": "dat", "defectMultiplier": 2.8},
      {"name": "object", "defectMultiplier": 3.0},
      {"name": "obj", "defectMultiplier": 3.0},
      {"name": "value", "defectMultiplier": 2.9},
      {"name": "val", "defectMultiplier": 2.9},
      {"name": "buffer", "defectMultiplier": 2.7},
      {"name": "buf", "defectMultiplier": 2.7},
      {"name": "arg", "alsoBans": "arg followed by digits (arg0, arg1, ...)", "reason": "names a position, not a role"}
    ],
    "exceptions": ["Single-character names (x, y, i, j, T, K, V) are always allowed"],
    "errorCode": "E11031",
    "documentation": "https://ek9.io/quality.html#naming-quality"
  },

  "codeQualityEnforcement": {
    "description": "Compile-time code quality rules unique to EK9. These exist in NO other language — AI will violate them on every attempt unless explicitly told. Ordered by AI violation frequency.",

    "stringInterpolationMandate": {
      "errorCode": "E11068",
      "rule": "3+ part string concatenation is a compile error",
      "rationale": "Forces readable interpolation, prevents unbounded concatenation chains",
      "example": {
        "wrong": "result <- first + \" \" + last",
        "correct": "result <- `${first} ${last}`"
      },
      "note": "2-part concatenation (a + b) is allowed. 3+ parts must use backtick interpolation."
    },

    "namedArgumentEnforcement": {
      "rules": [
        {
          "errorCode": "E11062",
          "rule": "4+ positional arguments require named arguments",
          "example": {
            "wrong": "connect(\"db\", 5432, \"reports\", 30)",
            "correct": "connect(host: \"db\", port: 5432, database: \"reports\", timeoutSeconds: 30)"
          }
        },
        {
          "errorCode": "E11061",
          "rule": "2+ Boolean literal arguments require named arguments",
          "example": {
            "wrong": "configure(true, false)",
            "correct": "configure(verbose: true, dryRun: false)"
          }
        }
      ],
      "syntax": "paramName: value",
      "note": "No other language mandates named arguments. AI training data contains zero examples of this constraint."
    },

    "magicLiteralDetection": {
      "rules": [
        {
          "errorCode": "E11064",
          "rule": "Bare numeric literal in comparison is a compile error",
          "example": {
            "wrong": "if retries > 3\n  timeout()",
            "correct": "maxRetries <- 3\nif retries > maxRetries\n  timeout()"
          }
        },
        {
          "errorCode": "E11065",
          "rule": "Same String literal 3+ times per file or 4+ per module requires a named value (numeric literals are not counted for repetition)",
          "example": {
            "wrong": "orderStatus <- \"pending\"\npaymentStatus <- \"pending\"\nshippingStatus <- \"pending\"",
            "correct": "pending <- \"pending\"\norderStatus <- pending\npaymentStatus <- pending\nshippingStatus <- pending"
          }
        }
      ],
      "exemptValues": [0, 1, -1, "0.0", "1.0"],
      "exemptTypes": ["Boolean", "Character", "RegEx", "Binary"],
      "note": "Extract numeric literals to named constants in 'defines constant' block."
    },

    "operatorKeywordShadowing": {
      "errorCode": "E11032",
      "rule": "Variable names that shadow operator keywords are banned",
      "banned": ["empty", "length", "contains", "abs", "sqrt", "close", "matches"],
      "fix": "Use descriptive alternatives: foundItems, isAvailable, searchPattern, textLength",
      "note": "Complements bannedIdentifiers (E11031) which covers non-descriptive names like temp, data, flag."
    },

    "discardedReturnValues": {
      "rules": [
        {
          "errorCode": "E11050",
          "rule": "Discarded operator return is a compile error",
          "example": "price.+(tax)  //ERROR: return value discarded"
        },
        {
          "errorCode": "E11051",
          "rule": "Discarded pure method/function return is a compile error",
          "example": "calculateTotal(items)  //ERROR: return value discarded"
        },
        {
          "errorCode": "E11052",
          "rule": "Discarded Result/Optional return silently swallows errors",
          "example": "parseJSON(input)  //ERROR: Result must be checked"
        }
      ],
      "fix": "Always capture return values: total <- calculateTotal(items)",
      "note": "Many languages allow ignoring return values. EK9 treats this as a bug."
    },

    "tautologicalExpressions": {
      "rules": [
        {"errorCode": "E08080", "rule": "Self-assignment: x := x"},
        {"errorCode": "E08081", "rule": "Self-comparison: x == x"},
        {"errorCode": "E08082", "rule": "Constant comparison: 1 == 1"},
        {"errorCode": "E08083", "rule": "Constant arithmetic: x - x, x / x"},
        {"errorCode": "E08084", "rule": "Redundant Boolean: b == true (use just b)"},
        {"errorCode": "E08085", "rule": "Logical tautology: a or not a"}
      ],
      "note": "AI copy-paste patterns frequently generate tautological expressions."
    },

    "confusinglySimilarNames": {
      "errorCode": "E11030",
      "rule": "Variables differing by 1-2 characters (Levenshtein distance) with same type are banned",
      "examples": ["data/dat", "userId/usersId", "count/counts"],
      "exemptions": ["Different types", "Constructor field shadowing", "Loop counters"],
      "research": "2.7x higher defect density (Butler et al., ICPC 2010)"
    },

    "classDesignAntiPatterns": {
      "rules": [
        {"errorCode": "E11022", "rule": "Class with 4+ service fields and 0 data fields should be 'defines component'"},
        {"errorCode": "E11023", "rule": "70%+ trait methods manually overridden — use 'by' delegation instead"},
        {"errorCode": "E11024", "rule": "'by' delegation + 3+ services — split into class + component"},
        {"errorCode": "E11025", "rule": "3+ services AND 3+ data fields — 'God Class', must decompose"}
      ]
    },

    "diInjectionLimits": {
      "rules": [
        {"errorCode": "E11040", "rule": "Max 4 injection fields per component"},
        {"errorCode": "E11041", "rule": "Similar dependencies should use a facade"},
        {"errorCode": "E11042", "rule": "Max 12 component registrations in a single application"},
        {"errorCode": "E11043", "rule": "Max 4 distinct injected types within a single method (fires at 5)"}
      ],
      "fix": "Split large components into focused sub-components with facades."
    },

    "dataClumpDetection": {
      "errorCode": "E11053",
      "rule": "3+ callables sharing 4+ parameters with matching types/names must extract to a record",
      "fix": "Create a record containing the repeated parameters and pass the record instead."
    },

    "typeTraversalLimit": {
      "errorCode": "E11054",
      "rule": "Max 3 type transitions in a method chain (Law of Demeter)",
      "example": {
        "wrong": "city <- order.getCustomer().getAddress().getRegion().getCity()",
        "correct": "city <- order.customerCity()"
      },
      "fix": "Delegate through intermediate methods to limit coupling."
    },

    "constantOrganization": {
      "rules": [
        {"errorCode": "E11066", "rule": "Constants scattered across 3+ files in a module must be consolidated"},
        {"errorCode": "E11067", "rule": "2+ files with 10+ total constants need a dedicated constants file"}
      ],
      "fix": "Use a single 'defines constant' block per module."
    },

    "unusedCaptureDetection": {
      "errorCode": "E11018",
      "rule": "Dynamic function/class captures a variable but never uses it",
      "fix": "Remove unused captures from the closure scope."
    },

    "referenceOrdering": {
      "errorCode": "E11026",
      "rule": "References (imports) must be sorted alphabetically",
      "research": "5-10% reduction in merge conflicts."
    }
  },

  "compilation": {
    "description": "EK9 compilation commands and flags",
    "incremental": {
      "compile": "ek9 -c main.ek9",
      "compileDebug": "ek9 -cg main.ek9",
      "compileDevDebug": "ek9 -cd main.ek9"
    },
    "full": {
      "recompile": "ek9 -C main.ek9",
      "recompileDebug": "ek9 -Cg main.ek9",
      "recompileDevDebug": "ek9 -Cd main.ek9",
      "cleanAll": "ek9 -Cl main.ek9"
    },
    "run": {
      "default": "ek9 main.ek9",
      "specificProgram": "ek9 -r ProgramName main.ek9",
      "shebang": "./main.ek9"
    },
    "optimization": {
      "O0": "No optimization (forced with tests)",
      "O1": "Light optimization",
      "O2": "Standard optimization (incompatible with -t)",
      "O3": "Aggressive optimization (incompatible with -t)"
    },
    "errorLevels": {
      "E0": "Minimal - single line",
      "E1": "Visual - Rust-style source display with caret markers",
      "E2": "Visual + 'Did you mean?' fuzzy matching suggestions",
      "E3": "Rich - full AI-oriented explanations with diagnosis, rationale, and examples",
      "E4": "Paradigm - concise summary of key design decisions (no break/continue/return, tri-state, closed types, automatic operators)",
      "E5": "Bootstrap - E4 paradigm summary plus complete forAI.json reference dump. Use once to learn EK9, then switch to E3",
      "E6": "Local agent briefing - slim forAI-local.json operational reference for fine-tuned local LLMs in ek9 -ai. Contains role, Oracle, intents, protocol, terrain, and top reminders (~1900 tokens)"
    },
    "help": {
      "generalHelp": "ek9 -h",
      "keywordHelp": "ek9 -h <keyword>",
      "errorCodeHelp": "ek9 -h Exxxx (e.g., ek9 -h E50001 — shows diagnosis, fix actions, examples for any error code)",
      "listAllKeywords": "ek9 -H",
      "questionAnswer": "ek9 -q <words> (EK9-focused: answer + code example)",
      "questionById": "ek9 -q <number> (fetch specific Q&A by ID, e.g., ek9 -q 45)",
      "questionMigration": "ek9 -qm <words> (migration-focused: answer + language comparisons)",
      "listAllQuestions": "ek9 -q",
      "aiNote": "Use 'ek9 -q <words>' for EK9 syntax and examples. Use 'ek9 -q <number>' to follow cross-links (e.g., 'See Q45'). Use 'ek9 -qm <words>' when comparing EK9 to other languages. Use 'ek9 -h Exxxx' to diagnose compiler errors."
    },
    "diAnalysis": {
      "compact": "ek9 -di main.ek9 (summary: registration counts, injection sites, health status)",
      "rich": "ek9 -di -E3 main.ek9 (full wiring map, injection sites, aspect chains, structured guidance)",
      "aiNote": "Run 'ek9 -di -E3' BEFORE modifying DI wiring to understand current registrations, ordering, and injection field counts"
    },
    "target": "ek9 -T java main.ek9 (Java is only target currently)",
    "verbose": "ek9 -v -c main.ek9",
    "aiRecommendation": "Use -E5 once to bootstrap, then -E3 for ongoing development. Use 'ek9 -h Exxxx' to diagnose any error. Use 'ek9 -di -E3' before modifying DI wiring. Use 'ek9 -q <words>' for EK9 syntax/examples, 'ek9 -qm <words>' for language comparisons.",
    "documentation": "https://ek9.io/commandline.html"
  },

  "testing": {
    "description": "EK9 testing commands, output formats, and coverage",
    "commands": {
      "runTests": "ek9 -t main.ek9",
      "listTests": "ek9 -tL main.ek9",
      "runGroup": "ek9 -tg groupname main.ek9",
      "showCoverage": "ek9 -tC main.ek9",
      "debug": "ek9 -d port main.ek9"
    },
    "outputFormats": {
      "t0": "Terse - for scripting and CI pipelines",
      "t1": "Human-readable (default with -t)",
      "t2": "JSON - programmatic analysis and AI tool integration",
      "t3": "JUnit XML - CI/CD integration",
      "t4": "Detailed coverage report - writes .ek9/coverage-detail.json with file:line for uncovered methods/branches",
      "t5": "Verbose coverage - lists BOTH covered AND uncovered items (for verification and debugging)",
      "t6": "Interactive HTML coverage report - writes .ek9/coverage/index.html with SVG charts, module breakdown, source views, dark/light theme, search, mobile-responsive"
    },
    "testDiscovery": "Programs marked with @Test in /dev directory and subdirectories are auto-discovered",
    "testGroups": "@Test: \"groupname\" syntax allows selective test execution with -tg",
    "coverage": {
      "threshold": "80% - automatic detailed report to .ek9/coverage-detail.json when below",
      "viewResults": "ek9 -tC main.ek9"
    },
    "constraint": "-t cannot be combined with -O2 or -O3 optimization flags",
    "aiRecommendation": "Use -t2 for JSON output in automated workflows, -t for human-readable during development",
    "documentation": "https://ek9.io/commandline.html#testing"
  },

  "packaging": {
    "description": "EK9 dependency management, versioning, packaging, and deployment",
    "dependencies": {
      "resolve": "ek9 -Dp main.ek9",
      "repository": "repo.ek9lang.org",
      "localCache": "$HOME/.ek9/lib",
      "note": "Triggers clean before resolving; dependencies declared in package construct"
    },
    "versioning": {
      "print": "ek9 -PV main.ek9",
      "increment": "ek9 -IV major|minor|patch|build main.ek9",
      "set": "ek9 -SV major.minor.patch main.ek9",
      "setFeature": "ek9 -SF major.minor.patch-feature main.ek9",
      "format": "major.minor.patch-build (e.g., 6.8.1-0) or major.minor.patch-feature-build (e.g., 6.8.0-specials-0)"
    },
    "package": "ek9 -P main.ek9",
    "installLocal": "ek9 -I main.ek9",
    "deploy": {
      "command": "ek9 -D main.ek9",
      "note": "Triggers -P and -Gk automatically",
      "generateKeys": "ek9 -Gk",
      "configFile": "$HOME/.ek9/config",
      "credentialsFile": "$HOME/.ek9/credentials"
    },
    "aiRecommendation": "Use -IV patch for bug fixes, -IV minor for new features, -IV major for breaking changes",
    "documentation": "https://ek9.io/commandline.html#packaging"
  },

  "projectStructure": {
    "description": "EK9 project directory structure and conventions",
    "layout": {
      "main.ek9": "Main source file with package construct defining module, version, and dependencies",
      ".ek9/": "Generated build artifacts directory (auto-created by compiler)",
      "dev/": "Development code — test programs (@Test), examples, templates. Not included in library packaging",
      "$HOME/.ek9/lib/": "Global dependency cache — resolved libraries stored here",
      "$HOME/.ek9/config": "Artifact server settings for deployment",
      "$HOME/.ek9/credentials": "Authentication details for artifact server"
    },
    "packageConstruct": {
      "description": "The package construct in main source declares project metadata and dependencies",
      "example": "defines package\n  version <- 1.0.0-0\n  description <- \"My EK9 library\"\n  deps <- {\n    \"org.example.lib\": \"2.0.0-0\"\n    }"
    },
    "devDirectory": {
      "description": "Programs in /dev are auto-discovered for testing",
      "convention": "Test files use @Test annotation, groups use @Test: \"groupname\"",
      "excluded": "Dev code is not included when the package is consumed as a library"
    },
    "documentation": "https://ek9.io/packaging.html"
  },

  "languageServer": {
    "description": "EK9 Language Server Protocol (LSP) integration",
    "start": "ek9 -ls main.ek9",
    "startWithHover": "ek9 -lsh main.ek9",
    "protocol": "stdin/stdout LSP protocol",
    "vscodeExtension": "Available for VSCode with syntax highlighting and real-time error reporting",
    "hoverHelp": "-lsh enables hover documentation for operators and symbols",
    "documentation": "https://ek9.io/commandline.html#languageserver"
  },

  "repl": {
    "description": "EK9 interactive Read-Eval-Print Loop",
    "start": "ek9 -repl",
    "startWithSuggestions": "ek9 -repl -E2",
    "modes": ["/function", "/class", "/record", "/trait", "/type"],
    "commands": {
      "edit": ":edit — opens $VISUAL or $EDITOR for multi-line editing",
      "editLine": ":edit N — edit line N in buffer",
      "delete": ":del N — delete line N",
      "insert": ":ins N — insert before line N",
      "undo": ":undo — undo last change",
      "save": ":save — save session",
      "load": ":load — load previous session"
    },
    "hoverHelp": "Ctrl+H shows symbol information in REPL",
    "documentation": "https://ek9.io/commandline.html#repl"
  },

  "environment": {
    "description": "EK9 environment variables and runtime configuration",
    "variables": {
      "EK9_COMPILER_MEMORY": "Compiler heap size (default: -Xmx512m), e.g., export EK9_COMPILER_MEMORY=\"-Xmx1024m\"",
      "EK9_APPLICATION_MEMORY": "Application heap size (default: -Xmx512m), e.g., export EK9_APPLICATION_MEMORY=\"-Xmx2048m\"",
      "EK9_TARGET": "Target architecture (default: java)",
      "EK9_PLAIN_TEXT": "Force plain text error output (no colors, no unicode)"
    },
    "stdinStdout": {
      "description": "EK9 programs integrate with Unix pipes and redirection",
      "examples": [
        "echo \"Hello\" | ek9 program.ek9",
        "ek9 filter.ek9 < input.txt > output.txt",
        "cat data.txt | ek9 filter.ek9 | sort | uniq"
      ],
      "classes": "Stdin(), Stdout(), Stderr()"
    },
    "setEnvFlag": "ek9 -e name=value main.ek9",
    "documentation": "https://ek9.io/commandline.html"
  },

  "exitCodes": {
    "description": "EK9 process exit codes for CI/CD integration and scripting. TWO LAYERS: the 'ek9' native wrapper (normal usage) follows Unix convention \u2014 0 means success. The underlying compiler jar (java -jar ek9c-jar-with-dependencies.jar) speaks an internal protocol the wrapper translates; callers invoking the jar DIRECTLY (AI agents, scripts) must read jarProtocol, NOT the wrapper view.",
    "jarProtocol": {
      "0": "A run-command was printed to stdout \u2014 the caller must exec it; the program's own exit code then passes through untouched",
      "1": "SUCCESS with nothing to run (e.g. -c/-C compile-only, -V, -Gk) \u2014 silent by Unix convention; the wrapper maps this to 0. Direct-jar callers: exit 1 + no output = the operation WORKED",
      "2+": "Error conditions \u2014 identical to the wrapper view below",
      "14": "Internal compiler error. Listed separately because 1 is the JVM's default exit status for an uncaught exception in main, and 1 also means SUCCESS here \u2014 before this code existed, a crashed compile was indistinguishable from a clean one."
    },
    "codes": {
      "0": "Success (wrapper view; jar: run-command printed \u2014 see jarProtocol)",
      "1": "Program's own exit code / wrapper exec failure (jar: success-nothing-to-run)",
      "2": "Invalid parameters",
      "3": "File access error",
      "4": "Invalid parameter combination",
      "5": "No programs found in source (also: the file is development source - under dev/ or a QA####_dev_ companion - which is never in the runnable artefact: stderr says <file> is development source: its programs run under -t, not directly)",
      "6": "Multiple programs exist \u2014 use -r to specify",
      "7": "Language Server failed to start",
      "8": "Compilation failed",
      "9": "Wrong number of program arguments",
      "10": "Argument type conversion failed",
      "11": "Test execution failed",
      "12": "Tests pass but coverage below required threshold",
      "13": "MCP server failed to start",
      "14": "Internal compiler error \u2014 an uncaught Throwable (e.g. OutOfMemoryError). The compile did NOT complete; artefacts are absent or partial. Distinct from 8 (compilation failed: the compiler worked, your source did not) \u2014 14 means the compiler itself failed. Raise EK9_COMPILER_MEMORY and retry.",
      "15": "-fuzz found one or more compiler crashes (crash files in ./fuzz-crashes/). Distinct from 11 (a unit test failed) so CI can gate a fuzz run on the exit code alone",
      "16": "DAP debug adapter failed to start (-dap)",
      "17": "A package dependency could not be resolved - not in ~/.ek9/lib (unpacked or zipped) and no remote repository yet, or the dependencies are circular or breach semantic versioning. The report names the dependency and version, the file:line declaring it and where it looked. Distinct from 2 (bad command line)"
    },
    "failureMarker": "When EK9 ITSELF fails (any code 2-17, including the generated entry point's 2/4/5/6 when it refuses its own command line - '-r' with no name, a program the jar does not have, none named among several - and 9/10 for arguments that do not fit the program), the FIRST stderr line is 'ek9: <reason> (exit N)', e.g. 'ek9: compilation failed (exit 8)'. A program's own exit (any code, 3/8/11 included) never carries it. Non-zero exit + first stderr line 'ek9: ... (exit N)' with the same N = EK9 failed; otherwise the code is the program's.",
    "programExitStatus": "When the wrapper runs YOUR program, the process status is the program's: 0 on normal completion; the returned Integer if the program declares one (unset -> 1); for an Exception nothing catches, its own exitCode (e.g. Exception(\"Fatal\", 3) exits 3), else 1; for a Panic, always 1. All after finally blocks and teardown have run. Only the exception that reaches the top counts: a wrapper without a code exits 1 even if its cause has one. Panic is raised only by the language (failed require, constrained-type breach, unset for-range bound): user code cannot create it (Panic(...) is E50060), throw it, catch it (E04030), or choose its code - to fail with a chosen code, throw an Exception carrying it and do not catch it. There is no exit() call. See ek9 -q 1431.",
    "programVersusCliExitCodes": "A program's exit status shares its numbers with the ek9 command's own codes (3, 8, 11 ...), so the number alone cannot say which stage produced it. A compile failure prints EK9 error lines and the program never runs; when EK9 ITSELF fails its first stderr line is 'ek9: <reason> (exit N)' (a program's own exit never carries it), and an uncaught Exception/Panic prints 'Exception in thread \"main\" ...'. 'ek9 -C' first separates the stages. Under -t a failed assert fails its test and ek9 exits 11 (the test runner's code). See ek9 -q 1437.",
    "ciExample": "ek9 -C main.ek9 && ek9 -t2 main.ek9 > test-results.json && ek9 -D main.ek9",
    "documentation": "https://ek9.io/commandline.html"
  },

  "developmentWorkflow": {
    "description": "Complete EK9 development lifecycle from creation to deployment",
    "steps": [
      {
        "phase": "create",
        "description": "Create source file with package construct defining module, version, and dependencies",
        "command": "touch myapp.ek9"
      },
      {
        "phase": "develop",
        "description": "Iterative development with incremental compilation",
        "command": "ek9 -c myapp.ek9"
      },
      {
        "phase": "diAnalysis",
        "description": "Inspect DI wiring before modifying injection (only if using components/applications)",
        "command": "ek9 -di -E3 myapp.ek9"
      },
      {
        "phase": "errorDiagnosis",
        "description": "Look up any compiler error for full diagnosis and fix actions",
        "command": "ek9 -h Exxxx"
      },
      {
        "phase": "run",
        "description": "Compile and execute the program",
        "command": "ek9 myapp.ek9"
      },
      {
        "phase": "test",
        "description": "Run all test programs in /dev directory",
        "command": "ek9 -t myapp.ek9"
      },
      {
        "phase": "coverage",
        "description": "Check test coverage meets 80% threshold",
        "command": "ek9 -tC myapp.ek9"
      },
      {
        "phase": "resolveDeps",
        "description": "Resolve dependencies from repo.ek9lang.org",
        "command": "ek9 -Dp myapp.ek9"
      },
      {
        "phase": "version",
        "description": "Increment version before release",
        "command": "ek9 -IV minor myapp.ek9"
      },
      {
        "phase": "package",
        "description": "Create deployment package",
        "command": "ek9 -P myapp.ek9"
      },
      {
        "phase": "installLocal",
        "description": "Install to local library for use by other projects",
        "command": "ek9 -I myapp.ek9"
      },
      {
        "phase": "deploy",
        "description": "Deploy to artifact server (generates keys if needed)",
        "command": "ek9 -D myapp.ek9"
      }
    ],
    "documentation": "https://ek9.io/commandline.html"
  },

  "streamPipelines": {
    "description": "EK9's replacement for loops needing break/continue. NOTE: for/while/do-while loops still exist for iteration with mutation, side effects, and I/O",
    "sources": [
      {"name": "cat", "purpose": "Create stream from collection, iterator, or enumeration"},
      {"name": "for", "purpose": "Range-based source: for i in 1 ... 10"}
    ],
    "intermediateOperations": [
      {"name": "filter", "purpose": "Keep items matching predicate (opposite of reject)"},
      {"name": "reject", "purpose": "Remove items matching predicate (opposite of filter)"},
      {"name": "map", "purpose": "Transform each item to a different type"},
      {"name": "sort", "purpose": "Order items using comparison function"},
      {"name": "group", "purpose": "Group ADJACENT items with == keys into Lists (sort first; optionally: group by key); must see every item"},
      {"name": "split", "purpose": "Start a new List at each item the predicate marks as a boundary; must see every item"},
      {"name": "join", "purpose": "Fold all items into one with a two-argument function; must see every item"},
      {"name": "uniq", "purpose": "Keep the first of each == item anywhere in the stream - global, not consecutive (optionally: uniq by key)"},
      {"name": "flatten", "purpose": "Expand nested collections: List of List -> individual items"},
      {"name": "head", "purpose": "Take first N items and stop pulling, back to the nearest sort/tail/join (replaces break)"},
      {"name": "tail", "purpose": "Take last N items; must see every item"},
      {"name": "skip", "purpose": "Discard first N items (replaces continue with counter)"},
      {"name": "tee", "purpose": "Side-copy into variable, continue pipeline; lazy - records only what flows past it (a later head limits it)"},
      {"name": "call", "purpose": "Invoke function delegate on each item"},
      {"name": "async", "purpose": "Invoke function delegate asynchronously"}
    ],
    "terminals": [
      {"name": "> sink", "purpose": "Direct output to collection or Stdout"},
      {"name": ">> collection", "purpose": "Append to existing collection"},
      {"name": "collect as Type", "purpose": "Materialize into new collection"}
    ],
    "replacesImperativePatterns": {
      "break": "head N (stop after N items)",
      "continue": "filter by condition (skip non-matching)",
      "loopWithSet": "uniq (deduplicate without manual tracking)",
      "nestedLoops": "group by key | map with transform | flatten"
    },
    "examples": [
      {
        "description": "Find first match (replaces loop + break)",
        "code": "result <- cat items | filter by isMatch | head 1 | collect as List of String"
      },
      {
        "description": "Skip invalid items (replaces continue)",
        "code": "outputs <- cat items | filter by isValid | map with transform | collect as List of Output"
      },
      {
        "description": "Sort, group, and process",
        "code": "cat library | sort by comparingAuthor | group by authorId | filter with sufficientBooks | map by orderOnPublishedDate | flatten > stdout"
      },
      {
        "description": "Collect all enum values",
        "code": "allSuits <- cat CardSuit | collect as List of CardSuit"
      }
    ],
    "documentation": "https://ek9.io/streamsAndPipelines.html"
  },

  "purityRules": {
    "description": "EK9's pragmatic purity model - compile-time enforcement limiting internal state mutation",
    "syntax": "functionName() as pure",
    "clarification": {
      "notHaskellPurity": "EK9 'pure' controls INTERNAL STATE MUTATION, not all side effects like Haskell",
      "ioIsSeparate": "I/O is essential and handled via IO types - not what 'pure' restricts",
      "whatPurePrevents": "Unexpected internal state changes that cause bugs, race conditions, unpredictable behavior",
      "whyPrintlnWorksInPure": "println doesn't mutate program state - it's an external I/O operation, a different concern"
    },
    "whatPureEnforces": {
      "canOnlyCallPureFunctions": "Pure functions/methods can only call other pure functions/methods (transitive)",
      "noDirectReassignment": "Cannot use := or : to reassign variables - only :=? (assign if unset) allowed",
      "cannotModifyParameters": "Cannot reassign or mutate incoming parameters (even :=? not allowed)",
      "cannotMutateFields": "Cannot modify instance fields/properties (except in constructors)",
      "canReadFields": "Can read fields and call pure methods on them"
    },
    "exceptions": {
      "returnVariable": "Return variable (<- rtn) can be assigned multiple times",
      "unsetVariables": "Variables that are UNSET can be assigned with :=?",
      "constructors": "Constructors can initialize fields with :=? (they MUST initialize state)",
      "loopVariables": "System-managed loop variables (for i in ...) are allowed"
    },
    "constructorPurity": {
      "rule": "All constructors in a class must have CONSISTENT purity (all pure or all non-pure)",
      "errorCode": "E05190",
      "pattern": "Use :=? to initialize properties in pure constructors"
    },
    "errorCodes": {
      "E08130": "NONE_PURE_CALL_IN_PURE_SCOPE - calling non-pure from pure context",
      "E08100": "NO_PURE_REASSIGNMENT - direct := assignment in pure context",
      "E05190": "MIX_OF_PURE_AND_NOT_PURE_CONSTRUCTORS - inconsistent constructor purity",
      "E05150": "SUPER_IS_PURE - non-pure function extending pure abstract",
      "E05160": "SUPER_IS_NOT_PURE - pure function extending non-pure abstract",
      "E08110": "NO_INCOMING_ARGUMENT_REASSIGNMENT - modifying incoming parameters"
    },
    "practicalGuidance": {
      "whenToUsePure": "Mark pure if it doesn't mutate any field/property state",
      "benefit": "Pure functions are deterministic, testable, and safe for concurrent execution",
      "pattern": "Use more local variables (like LLVM SSA) instead of reassignment"
    },
    "subtlety": {
      "creatingVsCalling": "Creating a non-pure function in pure context is OK - but CALLING it is NOT",
      "example": "calc :=? () is Calculation as function (result: number * 2)  // OK - creation is pure\ndoubled <- calc(22)  // ERROR E08130 - calling a non-pure function"
    },
    "documentation": "https://ek9.io/basics.html#pure"
  },

  "sanitizedTypes": {
    "description": "EK9's compile-time security model for input validation - 'Rejection at the Source'",
    "criticalRule": "The 'sanitized' modifier is ONLY valid on String parameters in function/method signatures",
    "philosophy": {
      "name": "Rejection at the Source",
      "meaning": "Sanitize external inputs at system entry points ONLY - once inside trusted boundary, data is clean",
      "benefit": "Security happens at compile-time through parameter declaration, not runtime checks scattered through code"
    },
    "parameterSemantics": {
      "criticalInsight": "Sanitized parameters are effectively PASS-BY-VALUE, not pass-by-reference",
      "explanation": "EK9 normally uses pass-by-reference (changes to parameter affect original). For sanitized parameters, a NEW copy is created (if safe) or an UNSET value is returned (if threat detected). The original is NEVER exposed.",
      "whyNoAliasing": "Because we always create a copy, aliasing the parameter would expose a reference that doesn't represent the sanitization semantics. Direct assignment is blocked to highlight this pass-by-value behavior."
    },
    "whereAllowed": {
      "allowed": ["Function parameters", "Method parameters", "Operator parameters", "Constructor parameters", "Program parameters", "Text method parameters"],
      "notAllowed": ["Variables declarations", "Return types", "Capture variables", "Call sites", "Extern declaration parameters (E07944)"]
    },
    "whereCleaned": {
      "rule": "The function or method that DECLARES the sanitized parameter cleans it on entry, before any of its code runs",
      "routesCovered": ["Direct call", "Call through a super type or trait", "Operator and switch case", "Stream stage, sink or tee", "Dispatcher handler", "Callback from built-in code (e.g. Optional.whenPresent)", "Program command-line argument"],
      "caller": "Writes nothing - 'f(sanitized x)' is E07942",
      "safeValue": "The receiver's own copy - the caller's String is never shared",
      "threat": "An unset String, plus one log line per matching detector"
    },
    "overrides": {
      "rule": "sanitized is part of the contract, like pure: an override may ADD it but never DROP it",
      "dropping": "E07940 - applies to class methods and trait implementations (against EVERY parent declaring the method: the super and each trait), functions that are 'is' a super function, dispatcher handlers (against the dispatcher entry point - a handler is reached before the entry point's body runs) and text locales",
      "adding": "Allowed - the override cleans its own input on every route, including calls through the super type"
    },
    "externDeclarations": {
      "rule": "sanitized is rejected on an extern parameter (E07944) - the compiler never generates an extern body, so it could not clean it",
      "fix": "Clean the input in the external implementation (InputSanitizer in Java), or wrap the extern call in an EK9 function with a sanitized parameter"
    },
    "threatTypes": [
      {"name": "SQL_INJECTION", "severity": 8, "description": "SQL injection patterns"},
      {"name": "SQL_INJECTION_SIGNATURE", "severity": 8, "description": "libinjection-style SQL detection"},
      {"name": "COMMAND_INJECTION", "severity": 9, "description": "Shell/command injection"},
      {"name": "PATH_TRAVERSAL", "severity": 6, "description": "Directory traversal (../)"},
      {"name": "XSS", "severity": 7, "description": "Cross-site scripting"},
      {"name": "XXE", "severity": 8, "description": "XML External Entity"},
      {"name": "SSTI", "severity": 7, "description": "Server-Side Template Injection"}
    ],
    "loggingFormats": {
      "description": "Controlled by EK9_SANITIZER_LOG_FORMAT environment variable",
      "formats": [
        {"name": "JSON", "default": true, "description": "Universal JSON format for any log shipper"},
        {"name": "ECS", "description": "Elastic Common Schema - for Elasticsearch, Splunk, Datadog"},
        {"name": "CEF", "description": "Common Event Format - for ArcSight, Azure Sentinel, QRadar"},
        {"name": "SIMPLE", "description": "Simple bracket format for testing/scripts"},
        {"name": "SILENT", "description": "Suppresses all output - for testing"}
      ]
    },
    "inputSanitizerClass": {
      "description": "Programmatic access to sanitization for manual validation",
      "methods": [
        {"name": "sanitize(input)", "returns": "Safe input or UNSET if threat"},
        {"name": "isSafe(input)", "returns": "Boolean true/false/unset"},
        {"name": "detectThreat(input)", "returns": "Threat type string or UNSET if safe"},
        {"name": "sanitizeWithoutPathChecks(input)", "returns": "For environment variables with legitimate paths"}
      ],
      "customization": "Cannot be directly modified. Companies must extend InputSanitizer and call methods manually."
    },
    "examples": {
      "correct": {
        "functionParameter": "processInput()\n  -> input as sanitized String\n  <- rtn as String: \"rejected\"\n  if input?\n    rtn: `accepted: ${input}`  // cleaned on entry - an attack arrives unset",
        "manualSanitization": "sanitizer <- InputSanitizer()\nif clean <- sanitizer.sanitize(userInput)\n  process(clean)"
      },
      "wrong": {
        "directAssignment": "local <- sanitizedParam  // ERROR: Cannot alias sanitized parameter",
        "variableDeclaration": "name <- sanitized getValue()  // ERROR E07943: Not on variables",
        "captureVariable": "made: (prefix: sanitized rawInput) is Formatter as pure function  // ERROR E07941: Not in captures",
        "callSite": "process(sanitized value)  // ERROR E07942: Not at call site",
        "overrideDrop": "override handle()\n  -> input as String  // ERROR E07940: the parent declares 'input as sanitized String'",
        "externParameter": "defines extern module lib\n\n  defines function\n    store()\n      -> input as sanitized String  // ERROR E07944: an extern body is never generated\n      <- rtn as String?"
      }
    },
    "errorCodes": {
      "E07910": "SANITIZED_PARAMETER_TYPE_INVALID - sanitized on a non-String parameter",
      "E07920": "SANITIZED_ONLY_ON_PARAMETERS - sanitized outside an incoming parameter",
      "E07930": "CANNOT_ASSIGN_FROM_SANITIZED - direct assignment from sanitized parameter (aliasing)",
      "E07940": "SANITIZED_MODIFIER_CANNOT_BE_DROPPED - an override dropped sanitized (adding it is allowed)",
      "E07941": "SANITIZED_NOT_ALLOWED_IN_CAPTURE - sanitized on captured variable",
      "E07942": "SANITIZED_NOT_ALLOWED_AT_CALL_SITE - sanitized used at a call site",
      "E07943": "SANITIZED_NOT_ALLOWED_IN_VARIABLE_DECLARATION - sanitized on a variable declaration",
      "E07944": "SANITIZED_NOT_ALLOWED_ON_EXTERN - sanitized on a parameter of an extern declaration"
    },
    "documentation": "https://ek9.io/sanitized.html"
  },

  "methodResolution": {
    "description": "EK9's cost-based method matching algorithm for overloaded methods",
    "criticalRule": "Methods are overloadable, functions are NOT - function names must be unique per module",
    "costBasedMatching": {
      "description": "Lower cost = better match. Percentage = 100.0 - totalCost",
      "costs": [
        {"name": "ZERO_COST", "value": 0.0, "meaning": "Exact type match - perfect"},
        {"name": "SUPER_COST", "value": 0.05, "meaning": "Match via superclass (per level)"},
        {"name": "TRAIT_COST", "value": 0.10, "meaning": "Match via trait (less specific than superclass)"},
        {"name": "COERCION_COST", "value": 0.5, "meaning": "Type promotion via #^ operator required"},
        {"name": "HIGH_COST", "value": 20.0, "meaning": "Match to 'Any' type - last resort only"},
        {"name": "INVALID_COST", "value": -1.0, "meaning": "No match possible"}
      ],
      "whyTraitCostsMoreThanSuper": "A class can implement many traits but only extends one superclass - superclass relationship is more specific"
    },
    "ambiguityDetection": {
      "description": "Two methods are ambiguous if their percentage match is within 0.001 tolerance",
      "whySmallTolerance": "Cost calculations use multipliers for multiple parameters, creating finer granularity",
      "errorCode": "E06140",
      "example": {
        "methods": "methodA(C1, C2) and methodA(C2, C1)",
        "call": "methodA(c2, c3) where c3 extends C2 extends C1",
        "costA": "c2→C1 (0.05) + c3→C2 (0.05) = 0.10",
        "costB": "c2→C2 (0.0) + c3→C1 (0.10) = 0.10",
        "result": "AMBIGUOUS - both have identical cost"
      }
    },
    "anyTypeHandling": {
      "description": "'Any' is the universal base type - root of EK9's type hierarchy",
      "cost": "HIGH_COST (20.0) - deliberately expensive to ensure specific types always preferred",
      "pattern": "Many built-in types have both specific and Any overloads",
      "example": "_eq(List other) costs 0.0, _eq(Any other) costs 20.0 - List version always wins"
    },
    "returnTypeMatching": {
      "description": "Return type compatibility is pass/fail only - no cost impact",
      "rule": "If return type specified in search and incompatible, method is rejected (not cost-adjusted)"
    },
    "noAutomaticPromotions": {
      "criticalRule": "EK9 has NO hidden/automatic type promotions",
      "explanation": "Everything is an object. Integer has explicit #^ promotion operator to Float",
      "benefit": "No surprises - all type conversions are visible in the code"
    },
    "functionResolution": {
      "description": "Functions CANNOT be overloaded - names must be unique per module",
      "errorIfDuplicate": "E02010 (DUPLICATE_NAME)",
      "resolution": "Simple parameter signature validation - no cost-based matching needed"
    },
    "errorCodes": {
      "E06140": "METHOD_AMBIGUOUS - multiple methods match with same cost",
      "E50060": "METHOD_NOT_RESOLVED - no matching method found",
      "E06270": "FUNCTION_PARAMETER_MISMATCH - function called with wrong parameters"
    },
    "documentation": "https://ek9.io/methods.html"
  },

  "operatorSemantics": {
    "description": "EK9 operator behavior - mutating vs non-mutating",
    "criticalWarning": "Mutating operators change the object in place and return nothing (++ and -- are statements, E07950) - so b <- a makes an ALIAS, not a copy, and a mutation through either name is seen through both",
    "mutatingOperators": {
      "description": "These operators MUTATE the target object in place; they return nothing, so they are statements",
      "operators": [
        {"symbol": "++", "method": "_inc", "note": "x++ mutates x in place - a statement, never part of an expression (y <- x++ is E07950)"},
        {"symbol": "--", "method": "_dec", "note": "x-- mutates x in place - a statement"},
        {"symbol": "+=", "method": "_addAss", "note": "Mutates in place"},
        {"symbol": "-=", "method": "_subAss", "note": "Mutates in place"},
        {"symbol": "*=", "method": "_mulAss", "note": "Mutates in place"},
        {"symbol": "/=", "method": "_divAss", "note": "Mutates in place"},
        {"symbol": ":=:", "method": "_copy", "note": "Copy INTO the target's own object, each type at its own level: a value copies its value, a List copies its element references; the generated default :=: is SHALLOW (each field refers to the source's object); a deep or selective copy is a hand-written operator :=: (ek9 -q deep or selective copy)"},
        {"symbol": ":^:", "method": "_replace", "note": "Replace content"},
        {"symbol": ":~:", "method": "_merge", "note": "Merge: never overwrites a set value; fills whatever is unset or missing, element by element, recursing into compatible nested structures; Lists append, Sets take the union"}
      ],
      "aliasingDanger": {
        "example": "x <- Integer(5)\ny <- x  // y and x are NOW THE SAME OBJECT!\nx++  // mutates that one object in place\n// x = 6, y = 6 (both reference the same Integer); y <- Integer(x) makes an independent copy",
        "warning": "This is DIFFERENT from C/C++/Java, where y = x copies a primitive value"
      },
      "bindingsAndObjects": {
        "rule": "b <- a makes b refer to the SAME object as a (b++ moves a). For an independent value construct one: b <- Integer(a)",
        "parameters": "An incoming parameter's BINDING cannot be reassigned (E08110), but it is NOT read-only: in non-pure code the object can be mutated in place (p += 1, list.add(x)) and the caller sees it, and it can be aliased and the alias reassigned",
        "readOnly": "Read-only is what pure provides: a pure body cannot mutate or reassign (E08100/E08120) and may call only pure code (E08130), so the guarantee carries through everything it calls"
      }
    },
    "nonMutatingOperators": {
      "description": "These operators return NEW objects - safe for functional programming",
      "operators": [
        {"symbol": "+", "method": "_add"},
        {"symbol": "-", "method": "_sub"},
        {"symbol": "*", "method": "_mul"},
        {"symbol": "/", "method": "_div"},
        {"symbol": "- (unary)", "method": "_negate"},
        {"symbol": "abs", "method": "_abs"},
        {"symbol": "==", "method": "_eq"},
        {"symbol": "<>", "method": "_neq"},
        {"symbol": "<", "method": "_lt"},
        {"symbol": ">", "method": "_gt"},
        {"symbol": "<=", "method": "_le"},
        {"symbol": ">=", "method": "_ge"},
        {"symbol": "<=>", "method": "_cmp"}
      ]
    },
    "documentation": "https://ek9.io/operators.html"
  },

  "operatorPrecedence": {
    "description": "The convention of C, Java and Python (Steve, 2026-10-07). Tightest binding first; within a level operators associate left unless marked right.",
    "levels": [
      "postfix ++ -- ! ?, the prefixes $ $$ #^ #< #> #? length abs sqrt ~, and 'is empty'",
      "^ (right-associative: 2 ^ 3 ^ 2 is 2 ^ (3 ^ 2) = 512)",
      "unary - (below ^: -x ^ 2 is -(x ^ 2), and a literal is no exception: -2 ^ 2 is -(2 ^ 2) = -4; write (-2) ^ 2 to square -2. Every postfix binds above it: -x is empty is -(x is empty))",
      "?: ?? <? <=? >? >=? (one coalescing level, right-associative; a mix with another operator, ?? included, needs parentheses, E08269)",
      "* / mod rem",
      "+ -",
      "<< >>",
      "<=> <~>",
      "< <= > >= matches contains in, and 'in a ... b' (name in names == expected compares the membership)",
      "== <> !=",
      "not (below the comparisons: not age == limit is not (age == limit), not name in names is not (name in names); it is never an operand of another operator unless parenthesised, except and/xor/or: a == (not b), never a == not b, and $ (not b), never $ not b (E08273); a and not b needs none; a negation is never applied to a negation - not, ~ and unary - are one operator, parenthesised or not: not not b, not (not b), ~~b, ~not b, - -x, -(-x), -not b are E08274 - write b (x), or one negation; -(a - b) and a - -b are legal)",
      "and",
      "xor",
      "or (a or b and c is a or (b and c))",
      "the ternary <- ... else (right-associative)"
    ],
    "documentation": "https://ek9.io/operators.html#precedence"
  },

  "coalescingOperators": {
    "description": "Operators that gracefully handle tri-state (absent/unset/set). Each of ??, ?:, <?, <=?, >?, >=? (and the ternary) returns ONE of its operands, so the operands must share a type: the same type or a subtype, one promoting (#^) to the other, or their nearest common super/trait - never an invented Any (E50030 at the operator). ??, ?: and the <? family never mix with a different binary operator without parentheses: (a + b) ?: c, not a + b ?: c; (a ?? b) + c, not a ?? b + c (E08269). A literal on the left of ?: is always set (E08094).",
    "operators": [
      {
        "symbol": "??",
        "name": "Null Coalescing",
        "meaning": "Return left unless it is ABSENT (no object), otherwise return right. A present-but-UNSET left (e.g. String()) passes straight through, so ?? does NOT default an unset value - use ?: for that",
        "example": "result <- possiblyAbsent ?? fallback"
      },
      {
        "symbol": "?:",
        "name": "Coalesce (Elvis)",
        "meaning": "Return left if SET, otherwise evaluate and return right (left unset or absent). The right side is evaluated ONLY when the left is unset. This is the operator for defaulting an unset value - NOT the same as ??",
        "example": "name <- input ?: \"Anonymous\""
      },
      {
        "symbol": "<? <=? >? >=?",
        "name": "Comparison Coalescing",
        "meaning": "Return one of the OPERANDS (never a Boolean): the set one when only one is set; the lesser (<? <=?) or greater (>? >=?) when both are set; unset when neither is. Both operands are always evaluated. Needs <=> on the type (E07620)",
        "example": "lowest <- first <? second"
      },
      {
        "symbol": ":=?",
        "name": "Assign-If-Unset",
        "meaning": "Fill the target only if it is currently UNSET (a :=? b is a := a ?: b); the right side is not evaluated otherwise",
        "example": "config :=? loadDefaults()  // Only loads if config unset"
      },
      {
        "symbol": "?",
        "name": "Is Set Check",
        "meaning": "Returns true if value is SET (has meaningful value)",
        "example": "if name?\n  process(name)"
      }
    ],
    "documentation": "https://ek9.io/operators.html#coalescing"
  },

  "requireAndAssert": {
    "description": "EK9 precondition and assertion mechanisms",
    "require": {
      "purpose": "Verify precondition — throws UNCATCHABLE exception if false (like panic)",
      "syntax": "require expression",
      "examples": [
        "require name?",
        "require age > 0",
        "require firstName? and lastName?",
        "require not true"
      ],
      "semantics": "When require fails, it indicates a serious unrecoverable defect. There is NO recovery — execution terminates. By design, require failures cannot drive control flow.",
      "useCases": [
        "Constructor argument validation: require id?",
        "Method preconditions: require amount > 0",
        "Invariant checking: require balance >= 0",
        "Defensive default constructor blocking: require not true"
      ]
    },
    "assert": {
      "purpose": "Test assertions in @Test programs — throws exception if false",
      "syntax": "assert expression",
      "note": "Use in @Test programs for test validation. Similar to require but specifically for test assertions."
    },
    "documentation": "https://ek9.io/testing.html#require"
  },

  "syntax": {
    "indentation": "2 spaces (not tabs)",
    "noSemicolons": true,
    "noCurlyBraces": true,
    "declaration": "name <- value",
    "typedDeclaration": "name as Type: value",
    "assignment": "name: value",
    "assignIfUnset": "name :=? value",
    "genericConstruction": "names <- List() of String - the parentheses come before the type arguments; where the target's type is declared a bare construction is completed from it: names as List of String: List()",
    "comments": {
      "singleLine": "// comment",
      "multiLine": "<?- comment -?>"
    }
  },

  "siteMap": {
    "description": "Complete EK9 documentation site map organized by category",
    "baseUrl": "https://ek9.io/",

    "gettingStarted": {
      "description": "Introduction and basics for new developers",
      "pages": [
        {"url": "index.html", "title": "About EK9", "description": "Overview and philosophy"},
        {"url": "introduction.html", "title": "Introduction", "description": "Getting started guide"},
        {"url": "structure.html", "title": "Structure", "description": "Module structure, indentation syntax"},
        {"url": "basics.html", "title": "Basics", "description": "Variables, types, tri-state semantics"}
      ]
    },

    "coreLanguage": {
      "description": "Core language constructs and syntax",
      "pages": [
        {"url": "operators.html", "title": "Operators", "description": "All EK9 operators including ?, :=?, ==, <=>"},
        {"url": "flowControl.html", "title": "Flow Control", "description": "Guards, conditionals, loops (NO break/continue/return)"},
        {"url": "exceptions.html", "title": "Exceptions", "description": "Error handling with try/catch"},
        {"url": "constants.html", "title": "Constants", "description": "Constant definitions"},
        {"url": "programs.html", "title": "Programs", "description": "Entry points and program structure"}
      ]
    },

    "types": {
      "description": "Type system and built-in types",
      "pages": [
        {"url": "builtInTypes.html", "title": "Built-in Types", "description": "String, Integer, Boolean, etc. (NO null)"},
        {"url": "collectionTypes.html", "title": "Collection Types", "description": "List, Dict, Optional, Result"},
        {"url": "standardTypes.html", "title": "Standard Types", "description": "Date, Time, Duration, etc."},
        {"url": "networkTypes.html", "title": "Network Types", "description": "HTTP, TCP, UDP types"},
        {"url": "sanitized.html", "title": "Input Sanitization", "description": "Sanitized types for security"},
        {"url": "enumerations.html", "title": "Enumerations", "description": "Enum definitions"},
        {"url": "records.html", "title": "Records", "description": "Data-focused aggregates (mutable — immutability via 'pure')"},
        {"url": "generics.html", "title": "Generics/Templates", "description": "Generic type parameters"}
      ]
    },

    "objectOriented": {
      "description": "Object-oriented programming constructs",
      "pages": [
        {"url": "classes.html", "title": "Classes", "description": "Class definitions (closed by default)"},
        {"url": "methods.html", "title": "Methods", "description": "Method definitions and dispatchers"},
        {"url": "traits.html", "title": "Traits", "description": "Interface-like abstractions"},
        {"url": "composition.html", "title": "Composition", "description": "Extension by composition with 'by'"},
        {"url": "inheritance.html", "title": "Inheritance", "description": "Type inheritance (use 'as open')"},
        {"url": "advancedClassMethods.html", "title": "Advanced Methods", "description": "Advanced class method patterns"}
      ]
    },

    "functional": {
      "description": "Functional programming features",
      "pages": [
        {"url": "functions.html", "title": "Functions", "description": "Function definitions (NO return statement)"},
        {"url": "dynamicFunctions.html", "title": "Dynamic Functions", "description": "First-class functions"},
        {"url": "dynamicClasses.html", "title": "Dynamic Classes", "description": "Runtime class creation"},
        {"url": "streamsAndPipelines.html", "title": "Streams/Pipelines", "description": "Stream processing (replaces break/continue)"}
      ]
    },

    "enterprise": {
      "description": "Enterprise and application features",
      "pages": [
        {"url": "components.html", "title": "Components", "description": "Component definitions"},
        {"url": "dependencyInjection.html", "title": "Dependency Injection", "description": "DI patterns"},
        {"url": "webServices.html", "title": "Web Services", "description": "REST services"},
        {"url": "commonDesignPatterns.html", "title": "Design Patterns", "description": "Common EK9 patterns"},
        {"url": "textProperties.html", "title": "Text/Properties", "description": "I18n and configuration"}
      ]
    },

    "tooling": {
      "description": "Development tools and compiler",
      "pages": [
        {"url": "commandline.html", "title": "Command Line", "description": "Compiler options including -E3/-E5 for AI"},
        {"url": "testing.html", "title": "Testing", "description": "Test framework and coverage"},
        {"url": "quality.html", "title": "Code Quality", "description": "Metrics and thresholds"},
        {"url": "packaging.html", "title": "Packaging", "description": "Building and distributing"},
        {"url": "repl.html", "title": "REPL", "description": "Interactive evaluation"}
      ]
    },

    "reference": {
      "description": "Reference documentation",
      "pages": [
        {"url": "errors.html", "title": "Error Index", "description": "All compiler errors with fixes"},
        {"url": "forAI.html", "title": "For AI Assistants", "description": "AI-specific guidance (HTML version)"}
      ]
    }
  },

  "commonAIMistakes": {
    "description": "Frequent mistakes AI assistants make when generating EK9 code",
    "syntaxMistakes": {
      "parenthesesAfterTypeArguments": {
        "description": "Writing a generic's '()' after its type arguments",
        "errorCode": "E06210",
        "severity": "COMPILE_ERROR",
        "wrong": "names <- List of String()",
        "correct": "names <- List() of String",
        "rule": "The parentheses belong to the generic's name, before 'of': 'G() of T'. With a declared type, 'names as List of String: List()' needs no type arguments at all; '<-' declares no type, so it always needs them."
      },
      "multipleArrows": {
        "description": "Using multiple -> for multiple parameters",
        "severity": "PARSE_FAILURE",
        "wrong": "myFunc()\n  -> name as String\n  -> count as Integer",
        "correct": "myFunc()\n  ->\n    name as String\n    count as Integer",
        "rule": "Single -> on its own line, then each parameter indented below"
      },
      "curlyBracesForBlocks": {
        "description": "Using {} for code blocks like C/Java",
        "severity": "PARSE_FAILURE",
        "wrong": "if condition { doSomething() }",
        "correct": "if condition\n  doSomething()",
        "rule": "Curly braces {} are ONLY for Dict literals: {1: \"one\", 2: \"two\"}"
      },
      "unclosedBacktickString": {
        "description": "Opening a String with a backtick and closing it with a double quote",
        "errorCode": "E01093",
        "severity": "PARSE_FAILURE",
        "wrong": "rtn: `${count} items\"",
        "correct": "rtn: `${count} items`",
        "rule": "Close a String with the delimiter that opened it. A backtick String never ends at a '\"', so it runs to the end of the file - E01093 is reported at the backtick that opened it."
      },
      "squareBracketsAsArrays": {
        "description": "Thinking [] creates arrays",
        "severity": "MISCONCEPTION",
        "correct": "numbers <- [1, 2, 3]  //a List of Integer, NOT an array",
        "rule": "EK9 has no arrays - [] is shorthand for List literals"
      },
      "pythonColonAfterStatements": {
        "description": "Adding : after if/for/while like Python",
        "severity": "PARSE_FAILURE",
        "wrong": "if condition:",
        "correct": "if condition",
        "rule": "No colon after control flow statements - just newline and indent"
      },
      "lambdaSyntax": {
        "description": "Using lambda/arrow function syntax from other languages",
        "severity": "PARSE_FAILURE",
        "wrong": "fn = (x) => x * 2",
        "correct": "doubler <- () is Transformer as function\n  rtn: number * 2",
        "rule": "EK9 uses 'dynamic functions': (captures) is FunctionType as function"
      },
      "cStyleForLoop": {
        "description": "Using C-style for(i=0; i<10; i++)",
        "severity": "PARSE_FAILURE",
        "wrong": "for (i = 0; i < 10; i++)",
        "correct": "for i in 0 ... 9",
        "rule": "Use 'for variable in range' or 'for item in collection'"
      },
      "enumValuesOnOneLine": {
        "description": "Enum values go one per line — several values on one line, even comma-separated, do not parse",
        "severity": "PARSE_FAILURE",
        "wrong": "CardSuit\n  Hearts, Diamonds, Clubs, Spades",
        "correct": "CardSuit\n  Hearts\n  Diamonds\n  Clubs\n  Spades",
        "rule": "Each enum value on its own line at one indent level deeper than the type name (a trailing comma after a value is allowed: 'Hearts,'), never several values on one line"
      },
      "catWithRange": {
        "description": "Using 'cat' with a numeric range — 'cat' takes collections or types, not ranges",
        "severity": "PARSE_FAILURE",
        "wrong": "cat 1 ... 10 | map by transform | collect as List of Integer",
        "correct": "squares <- for i in 1 ... 10 | map with transform | collect as List of Integer",
        "rule": "'cat' streams from collections (cat myList) or enumeration types (cat Colour). Use 'for i in start ... end' to generate ranges in stream pipelines."
      }
    },
    "aggregateConstructionRules": {
      "description": "Mandatory rules for declaring records / classes / components — most AI-generated test fixtures violate one of these on the first try. Each rule is enforced by the EK9 compiler with a specific error code.",

      "fieldInitialisationRequired": {
        "description": "Every property/field on a record / class / component must be initialised at declaration OR through a developer-coded constructor",
        "errorCodes": ["E08070", "E07170", "E08180"],
        "rule": "Fields of form 'name as Type' must have an initialiser: 'name as Type: defaultExpression'. The `?` marker syntax 'name as Type?' indicates 'allowed unset', NOT 'no default needed' — it still requires the field to be set via constructor, and the no-argument constructor must then be made private: 'default private Point()' (E07175).",
        "wrong": "defines record\n  Point\n    x as Float\n    y as Float",
        "correct": "defines record\n  Point\n    x as Float: 0.0\n    y as Float: 0.0\n    default operator",
        "alternativeCorrect": "defines record\n  Point\n    x as Float?\n    y as Float?\n\n    default private Point()\n\n    Point()\n      ->\n        xArg as Float\n        yArg as Float\n      this.x: xArg\n      this.y: yArg\n\n    default operator"
      },

      "isSetOperatorRequired": {
        "description": "Aggregates (record / class / component) with declared fields MUST provide the '?' (isSet) operator — required by EK9's tri-state semantics. Applies equally to records AND classes — it is NOT a record-only rule.",
        "errorCodes": ["E07200", "E07235"],
        "rule": "Either use 'default operator ?' (compiler synthesises from field-? AND of all fields) or 'override operator ? as pure' with custom body. Records can additionally use bare 'default operator' which synthesises ? plus every other defaultable operator at once. Classes can mix 'default operator ?' with custom operators in any order subject to the member-ordering rule.",
        "wrong": "defines class\n  Greeter\n    name as String: \"hi\"\n    greet() as pure\n      <- result as String: name",
        "correct": "defines class\n  Greeter\n    name as String: \"hi\"\n\n    greet() as pure\n      <- result as String: name\n\n    default operator ?"
      },

      "concreteRecordNeedsAField": {
        "description": "A record exists only to carry data (it cannot have methods, E07290), so a CONCRETE record with no fields, counting inherited ones, is a compile error. An abstract record may have none: it is the root of a record hierarchy. A sub-record that inherits fields needs none of its own.",
        "errorCode": "E07237",
        "rule": "Give the record the field(s) it carries; use a class or component if it carries behaviour (a class or component with no fields is set by being present); mark it 'as abstract' if it is the polymorphic root; use an enumeration for a marker of a fixed set of values.",
        "wrong": "defines record\n  Reading\n    default operator",
        "correct": "defines record\n  Reading\n    celsius <- 21.5\n    default operator"
      },

      "abstractOperatorOnlyWithoutFields": {
        "description": "A sub-type's 'default operator $' / '$$' / '#?' below an ABSTRACT super operator covers only the sub-type's own fields, so an abstract '$', '$$' or '#?' on a type that HAS fields (counting inherited ones) is a compile error at the abstract operator - the fields would silently be left out. A field-less abstract root, or a trait, may keep the operator abstract.",
        "errorCode": "E07185",
        "rule": "Where the data is, give '$' / '$$' / '#?' a body or 'default operator X' (a hand-written body when the fields are not to be exposed); keep the operator abstract only on a field-less root or a trait.",
        "wrong": "defines class\n  Shape as abstract\n    name as String: String()\n    operator $ as pure abstract\n      <- rtn as String?\n    default operator ?",
        "correct": "defines class\n  Shape as abstract\n    name as String: String()\n    default operator $\n    default operator ?"
      },

      "subTypeAddingFieldsDeclaresItsOwnOperators": {
        "description": "A type that ADDS fields must declare its own '$', '$$' and ':=:' wherever it would otherwise inherit one from a type above it (as E07235 requires of '?'): the inherited operator was written for the super's fields and cannot know the new ones. A 'default operator' calls the NEAREST implementation above it, so a field-less type in the middle of a hierarchy needs no operators of its own. Not for '#?', '==' or '<=>': sameness is declared once, at the root.",
        "errorCode": "E07238",
        "rule": "On every type that adds fields below a type with '$', '$$' or ':=:', add 'default operator $' (and '$$', ':=:') - or the bare 'default operator' - or write the operator by hand.",
        "wrong": "defines class\n  Base as open\n    id as Integer: 1\n    default operator ?\n    default operator $\n  Leaf extends Base\n    name as String: \"leaf\"\n    default operator ?",
        "correct": "defines class\n  Base as open\n    id as Integer: 1\n    default operator ?\n    default operator $\n  Leaf extends Base\n    name as String: \"leaf\"\n    default operator ?\n    default operator $"
      },

      "memberOrderingFieldsMethodsOperators": {
        "description": "EK9 enforces a strict body-member ordering inside classes / records / components: ALL fields first, THEN methods, THEN operators. Mixing the three categories or putting methods before fields is a parse-level error.",
        "errorCode": "E01086",
        "rule": "Body order: fields → methods → operators. Within each band the order is flexible; between bands the rule is absolute.",
        "wrong": "defines class\n  Greeter\n    default operator ?\n    name as String: \"hi\"\n    greet() as pure\n      <- result as String: name",
        "correct": "defines class\n  Greeter\n    name as String: \"hi\"\n\n    greet() as pure\n      <- result as String: name\n\n    default operator ?"
      },

      "minimalCompilingAggregateTemplate": {
        "description": "The smallest aggregate fixture that compiles cleanly under the EK9 quality gate. Use as the starting template when writing test fixtures or example code.",
        "record": "#!ek9\ndefines module com.example.geo\n\n  defines record\n    Point\n      x as Float: 0.0\n      y as Float: 0.0\n      default operator\n\n//EOF",
        "class": "#!ek9\ndefines module com.example.greet\n\n  defines class\n    Greeter\n      greeting as String: \"Hello\"\n\n      greet() as pure\n        <- result as String: greeting\n\n      default operator ?\n\n//EOF",
        "note": "Records can use bare 'default operator' to get all defaults at once; classes typically need at least 'default operator ?'. Both must satisfy fieldInitialisationRequired and memberOrderingFieldsMethodsOperators."
      }
    },

    "semanticMistakes": {
      "usingExcludedKeywords": {
        "description": "Using break, continue, return, null",
        "errorCodes": ["E01070", "E01071", "E01072", "E01073"],
        "rule": "These keywords do not exist - see $.excludedFeatures"
      },
      "instanceofOrCasting": {
        "description": "Trying to check or cast types at runtime",
        "rule": "No instanceof, no casting - use dispatcher pattern only"
      },
      "automaticTypePromotion": {
        "description": "Assuming Integer converts to Float automatically",
        "rule": "All promotions explicit via #^ operator: intVal#^"
      },
      "overloadingFunctions": {
        "description": "Creating multiple functions with same name",
        "errorCode": "E01040",
        "rule": "Functions cannot be overloaded - only methods can"
      },
      "extendingClosedTypes": {
        "description": "Extending List, Dict, Optional, etc.",
        "errorCode": "E05030",
        "rule": "Built-in generic types are closed - use composition"
      },
      "reassigningInPure": {
        "description": "Using := in pure functions",
        "errorCode": "E08100",
        "rule": "Only :=? (assign if unset) allowed in pure contexts"
      },
      "aliasingSanitized": {
        "description": "Direct assignment from sanitized parameter",
        "errorCode": "E07930",
        "rule": "Cannot alias sanitized params - pass-by-value semantics"
      },
      "incrementInExpression": {
        "description": "Using x++ in expressions like y <- x++",
        "errorCode": "E07950",
        "rule": "++/-- are statement-only, not expression operators"
      },
      "manualJsonSerialization": {
        "description": "Writing custom JSON conversion instead of using default operator $$",
        "rule": "Use 'default operator $$' on records/classes for auto-generated JSON. List of T also has $$ operator.",
        "example": {
          "wrong": "toJSON()\n  -> c as Customer\n  <- rtn as String: `{ \"name\": \"${c.name}\" }`",
          "correct": "Customer\n  name as String: String()\n  default operator ?\n  default operator $$\n//Usage: json <- $$customer"
        }
      },
      "manualStringSerialization": {
        "description": "Writing custom String conversion instead of using default operator $",
        "rule": "Use 'default operator $' for auto-generated string representation",
        "example": {
          "wrong": "toString()\n  -> c as Customer\n  <- rtn as String: `${c.name} ${c.surname}`",
          "correct": "Customer\n  name as String: String()\n  surname as String: String()\n  default operator ?\n  default operator $\n//Usage: str <- $customer"
        }
      },
      "unusedTraitDefinition": {
        "description": "Defining a trait but implementing its operations as standalone functions instead of a class",
        "rule": "If you define a trait, always implement it with 'class X with trait of TraitName'. Never define a trait and then ignore it.",
        "severity": "DESIGN_FLAW"
      },
      "unusedParameter": {
        "description": "Declaring a parameter that is never referenced in the function/method body",
        "errorCode": "E08091",
        "rule": "Every declared parameter must be used. Remove unused parameters or use them in the body.",
        "exemptions": [
          "Abstract methods/functions (no body)",
          "Override methods (signature forced by parent)",
          "Dispatcher methods (must accept dispatched type)",
          "Operators (fixed semantics)",
          "Functions explicitly extending another function",
          "Methods on parameterised types (signature forced by generic contract)"
        ],
        "severity": "COMPILE_ERROR"
      },
      "operatorQuestionMustBePure": {
        "description": "operator ? must ALWAYS be declared 'as pure' — it is a query, never mutates",
        "errorCode": "E07500",
        "wrong": "override operator ?\n  <- rtn as Boolean: name?",
        "correct": "override operator ? as pure\n  <- rtn as Boolean: name?",
        "rule": "operator ? checks if a value is set — this is inherently pure. The compiler requires 'as pure' on every ? operator declaration.",
        "severity": "COMPILE_ERROR"
      },
      "enumSwitchExhaustivenessAndDefault": {
        "description": "Switch expression on enum requires BOTH all enum cases AND a default clause",
        "errorCodes": ["E07310", "E07330"],
        "wrong": "label <- switch status\n  <- rtn as String?\n  case Status.Active\n    rtn: \"active\"\n  default\n    rtn: \"other\"",
        "correct": "label <- switch status\n  <- rtn as String?\n  case Status.Active\n    rtn: \"active\"\n  case Status.Inactive\n    rtn: \"inactive\"\n  default\n    rtn: \"unknown\"",
        "rule": "When switching on an enumeration as an EXPRESSION (<- rtn), list ALL enum values explicitly AND include a default. E07310 fires if cases are missing, E07330 fires if default is missing.",
        "severity": "COMPILE_ERROR"
      },
      "copyConstructorInPureContext": {
        "description": "Calling a copy constructor like TypeName(existingVar) inside a pure method when the constructor is not pure",
        "errorCode": "E08130",
        "wrong": "status() as pure\n  <- rtn as ConnectionStatus: ConnectionStatus(currentStatus)",
        "correct": "status()\n  <- rtn as ConnectionStatus: ConnectionStatus(currentStatus)\n\n// OR if method must be pure, return the field directly if semantics allow it",
        "rule": "Copy constructors may not be marked pure. If you need to return a copy from a pure method, either remove 'as pure' from the method, or find a pure alternative. Use 'ek9 -h <Type>' to check if the copy constructor is pure.",
        "severity": "COMPILE_ERROR"
      },
      "positionalArgumentsMustBeNamed": {
        "description": "Passing 4+ arguments positionally, or two or more literal true/false, without naming them",
        "errorCode": "E11062",
        "wrong": "line <- OrderLine(9.99, 2, 0.1, 0.2)\nconfigure(true, false)",
        "correct": "line <- OrderLine(price: 9.99, quantity: 2, discount: 0.1, taxRate: 0.2)\nconfigure(verbose: true, dryRun: false)",
        "rule": "E11062 at 4+ arguments; E11061 at 2+ LITERAL true/false whatever the arity, so two arguments is enough — a Boolean-typed VARIABLE is not a literal and does not count. E06240: all named or none. E06250: each name must be the DECLARED parameter name, in declaration order — read the signature ('ek9 -h <Type>', or the Oracle) rather than invent a label.",
        "severity": "COMPILE_ERROR"
      },
      "inventedMemberOrTypeNames": {
        "description": "Calling a method, or naming a type or function, that was never read — guessed from another language",
        "errorCode": "E50060",
        "wrong": "total <- order.getTotl()\nlist.add(item)",
        "correct": "total <- order.getTotal()\nlist += item",
        "rule": "E50001 'not resolved', E50010 'type not resolved' and E50060 'method/function not resolved' are the commonest failures of all. Read the API first ('ek9 -h <Type>', or the Oracle's effective-API enquiry). When it does happen the diagnostic names the nearest real candidates — at -E2 in the message ('did you mean ...?'), and as a 'suggestions' list on a tool refusal — so resend with one of those rather than guess a second time.",
        "severity": "COMPILE_ERROR"
      },
      "doubleQuotedInterpolation": {
        "description": "Writing \"${count} items\" - a double-quoted String never interpolates (double quotes DO in Kotlin, Groovy, Dart, PHP and the shells)",
        "errorCode": "E07901",
        "wrong": "stdout.println(\"${count} items\")",
        "correct": "stdout.println(`${count} items`)",
        "rule": "Only a backtick String interpolates ${...}. A double-quoted String holding ${ is a compile error, and the error spells out both rewrites. For the literal characters write \\${ in a backtick String - `\\${count} items` - because \\$ is not an escape in a double-quoted String. In a backtick String a $ that opens no interpolation is escaped the same way: `cost \\$5 for ${count}`.",
        "severity": "COMPILE_ERROR"
      }
    },
    "assignmentConfusion": {
      "description": "EK9 has multiple assignment forms",
      "forms": [
        {"syntax": "name <- value", "meaning": "Declaration with type INFERENCE (most common)"},
        {"syntax": "name as Type: value", "meaning": "Declaration with EXPLICIT type, assign with :"},
        {"syntax": "name as Type := value", "meaning": "Declaration with EXPLICIT type, assign with :="},
        {"syntax": "name: value", "meaning": "REASSIGNMENT to existing variable"},
        {"syntax": "name := value", "meaning": "REASSIGNMENT to existing variable"},
        {"syntax": "name :=? value", "meaning": "Assign ONLY if currently unset"}
      ],
      "keyPoint": "<- is NOT the only way to declare - it's just the type-inference form"
    }
  },

  "errorCodeIndex": {
    "description": "Lookup from error code to forAI.json path — AI assistants use this to find structured guidance for any compiler error",

    "E01070": "excludedFeatures.break",
    "E01071": "excludedFeatures.continue",
    "E01072": "excludedFeatures.return",
    "E01073": "excludedFeatures.null",
    "E01074": "excludedFeatures.semicolon",
    "E01075": "excludedFeatures.new",
    "E01076": "excludedFeatures.goto",
    "E01077": "excludedFeatures.def",
    "E01078": "excludedFeatures.elif",
    "E01079": "excludedFeatures.None",
    "E01080": "excludedFeatures.self",
    "E01081": "excludedFeatures.listComprehension",
    "E01082": "excludedFeatures.multipleArgumentArrows",
    "E01083": "excludedFeatures.multipleReturnArrows",
    "E01094": "excludedFeatures.close",

    "E05030": "closedByDefault",

    "E11010": "qualityMetrics.cyclomaticComplexity",
    "E11021": "qualityMetrics.cognitiveComplexity",
    "E11011": "qualityMetrics.nestingDepth",
    "E11012": "qualityMetrics.statementCount",
    "E11013": "qualityMetrics.operatorsPerExpression",
    "E11014": "qualityMetrics.cohesion",
    "E11015": "qualityMetrics.coupling",
    "E11019": "qualityMetrics.inheritanceDepth",

    "E11031": "bannedIdentifiers",

    "E08070": "commonAIMistakes.aggregateConstructionRules.fieldInitialisationRequired",
    "E07170": "commonAIMistakes.aggregateConstructionRules.fieldInitialisationRequired",
    "E08180": "commonAIMistakes.aggregateConstructionRules.fieldInitialisationRequired",
    "E07200": "commonAIMistakes.aggregateConstructionRules.isSetOperatorRequired",
    "E07235": "commonAIMistakes.aggregateConstructionRules.isSetOperatorRequired",
    "E07237": "commonAIMistakes.aggregateConstructionRules.concreteRecordNeedsAField",
    "E07185": "commonAIMistakes.aggregateConstructionRules.abstractOperatorOnlyWithoutFields",
    "E07238": "commonAIMistakes.aggregateConstructionRules.subTypeAddingFieldsDeclaresItsOwnOperators",
    "E01086": "commonAIMistakes.aggregateConstructionRules.memberOrderingFieldsMethodsOperators",

    "E08100": "purityRules",
    "E08110": "purityRules",
    "E05150": "purityRules",
    "E05160": "purityRules",
    "E05190": "purityRules",

    "E07910": "sanitizedTypes",
    "E07920": "sanitizedTypes",
    "E07930": "sanitizedTypes",
    "E07940": "sanitizedTypes",
    "E07941": "sanitizedTypes",
    "E07942": "sanitizedTypes",
    "E07943": "sanitizedTypes",
    "E07944": "sanitizedTypes",

    "E06140": "methodResolution",
    "E50060": "methodResolution",
    "E06270": "methodResolution",

    "E01040": "commonAIMistakes.semanticMistakes.overloadingFunctions",
    "E07950": "commonAIMistakes.semanticMistakes.incrementInExpression",
    "E07901": "commonAIMistakes.semanticMistakes.doubleQuotedInterpolation",
    "E01093": "commonAIMistakes.syntaxMistakes.unclosedBacktickString",
    "E08091": "commonAIMistakes.semanticMistakes.unusedParameter",

    "E07120": "dispatcherPattern",
    "E07820": "dispatcherPattern",
    "E05170": "dispatcherPattern",
    "E05180": "dispatcherPattern",

    "E06180": "accessModifiers",

    "E07310": "commonAIMistakes.semanticMistakes.enumSwitchExhaustivenessAndDefault",
    "E07330": "commonAIMistakes.semanticMistakes.enumSwitchExhaustivenessAndDefault",
    "E07500": "commonAIMistakes.semanticMistakes.operatorQuestionMustBePure",
    "E08130": "commonAIMistakes.semanticMistakes.copyConstructorInPureContext",

    "E08080": "codeQualityEnforcement.tautologicalExpressions",
    "E08081": "codeQualityEnforcement.tautologicalExpressions",
    "E08082": "codeQualityEnforcement.tautologicalExpressions",
    "E08083": "codeQualityEnforcement.tautologicalExpressions",
    "E08084": "codeQualityEnforcement.tautologicalExpressions",
    "E08085": "codeQualityEnforcement.tautologicalExpressions",

    "E11018": "codeQualityEnforcement.unusedCaptureDetection",
    "E11022": "codeQualityEnforcement.classDesignAntiPatterns",
    "E11023": "codeQualityEnforcement.classDesignAntiPatterns",
    "E11024": "codeQualityEnforcement.classDesignAntiPatterns",
    "E11025": "codeQualityEnforcement.classDesignAntiPatterns",
    "E11026": "codeQualityEnforcement.referenceOrdering",
    "E11030": "codeQualityEnforcement.confusinglySimilarNames",
    "E11032": "codeQualityEnforcement.operatorKeywordShadowing",
    "E11040": "codeQualityEnforcement.diInjectionLimits",
    "E11041": "codeQualityEnforcement.diInjectionLimits",
    "E11042": "codeQualityEnforcement.diInjectionLimits",
    "E11043": "codeQualityEnforcement.diInjectionLimits",
    "E11050": "codeQualityEnforcement.discardedReturnValues",
    "E11051": "codeQualityEnforcement.discardedReturnValues",
    "E11052": "codeQualityEnforcement.discardedReturnValues",
    "E11053": "codeQualityEnforcement.dataClumpDetection",
    "E11054": "codeQualityEnforcement.typeTraversalLimit",
    "E11061": "codeQualityEnforcement.namedArgumentEnforcement",
    "E11062": "codeQualityEnforcement.namedArgumentEnforcement",
    "E11064": "codeQualityEnforcement.magicLiteralDetection",
    "E11065": "codeQualityEnforcement.magicLiteralDetection",
    "E11066": "codeQualityEnforcement.constantOrganization",
    "E11067": "codeQualityEnforcement.constantOrganization",
    "E11068": "codeQualityEnforcement.stringInterpolationMandate"
  },

  "aiQuickReference": {
    "description": "Most commonly needed pages for AI assistants",
    "forErrors": "https://ek9.io/errors.html",
    "forQualityIssues": "https://ek9.io/quality.html",
    "forFlowControl": "https://ek9.io/flowControl.html",
    "forStreams": "https://ek9.io/streamsAndPipelines.html",
    "forTypes": "https://ek9.io/builtInTypes.html",
    "forTesting": "https://ek9.io/testing.html",
    "forCommands": "https://ek9.io/commandline.html",
    "forPackaging": "https://ek9.io/packaging.html",
    "forDependencies": "https://ek9.io/packaging.html#dependencies",
    "forComprehensiveGuide": "https://ek9.io/forAI.html"
  },

  "oracleKnowledgeBase": {
    "description": "The EK9 Oracle is an in-process knowledge base of compiler-validated Q&A entries with working code snippets. Both frontier and local LLMs MUST consult the Oracle before writing code.",
    "whatItContains": {
      "qaEntries": "565+ Q&A entries across 49 categories (growing toward 2000+)",
      "codeSnippets": "Every Q&A contains working EK9 code that compiles against the current compiler",
      "migrationContext": "Language comparison notes for developers coming from Java, Python, C#, etc.",
      "errorPatterns": "Common mistakes with error codes and corrected examples"
    },
    "howToQuery": {
      "byKeywords": "ek9 -q <words> — BM25F-ranked search across questions, answers, keywords",
      "byId": "ek9 -q <number> — fetch specific Q&A by ID (e.g., ek9 -q 45)",
      "withMigration": "ek9 -qm <words> — includes language comparison context in results",
      "byProtocol": "ek9 -qp <words> — search protocol-specific Q&A entries for agent coordination",
      "listAll": "ek9 -q — list all categories and entry counts"
    },
    "oracleFirstWorkflow": {
      "description": "The Oracle enables a design-first workflow that inverts the industry-standard generate-then-fix cycle",
      "steps": [
        "DECOMPOSE: Break the user's request into design components (file I/O, validation, DI, etc.)",
        "CONSULT: Query the Oracle for each component — ask-oracle returns proven, compiled snippets",
        "ASSESS: Check coverage — if all components have snippets, proceed. If gaps exist, report them",
        "COMPOSE: Assemble the solution from Oracle snippets, adapting to the specific requirement",
        "VERIFY: Compile and expect near-clean result (1-2 fix cycles, not 8)"
      ],
      "whyThisWorks": "Oracle snippets are compiler-validated against the current compiler version. Starting from proven patterns means the first attempt is usually correct. Code-first approaches that guess from general training data take 5-8x more compile cycles.",
      "tokenSavings": "An Oracle-first approach that starts from snippets needs 1-2 compile cycles. A code-first approach needs 8. Over a session with 10 tasks, that is 15 compile cycles vs 80."
    },
    "criticalRule": "ALWAYS consult the Oracle before writing EK9 code. The Oracle contains patterns that are guaranteed to compile. Generating from general training data wastes tokens on doomed implementations."
  },

  "aiAgentArchitecture": {
    "description": "When running inside ek9 -ai, LLMs operate in a two-tier system with structured delegation and escalation protocols",
    "twoTierModel": {
      "frontier": "Cloud LLM (e.g., Claude) — handles architectural reasoning, complex multi-file analysis, design decisions",
      "local": "Local LLM (e.g., Qwen2.5-Coder-32B) — handles routine compile-fix loops, Oracle consultation, symbol lookups, test execution",
      "ratio": "70-80% of work is handled locally (zero token cost), 20-30% by frontier (targeted, high-value reasoning)"
    },
    "threeMessageTypes": {
      "delegation": {
        "direction": "Frontier -> Local",
        "purpose": "Assign a scoped task (investigation, implementation, or validation)",
        "keyFields": ["taskId", "delegationType", "objective", "questions/instructions", "constraints.responseBudget", "terrainBrief"],
        "protocolQuery": "ek9 -qp delegation brief format"
      },
      "escalation": {
        "direction": "Local -> Frontier",
        "purpose": "Request help when stuck (repeated failure, low confidence, out of scope, oracle gap)",
        "keyFields": ["taskId", "originalObjective", "escalationReason", "currentState", "attemptHistory", "specificQuestion"],
        "criticalRule": "Escalation requests must be self-contained — the frontier should be able to help without re-investigating",
        "protocolQuery": "ek9 -qp escalation request format"
      },
      "progress": {
        "direction": "Local -> Frontier (fire-and-forget)",
        "purpose": "Lightweight status update during long delegations (under 100 tokens)",
        "keyFields": ["taskId", "progress.phase", "confidence", "estimatedCompletionSeconds"],
        "protocolQuery": "ek9 -qp progress update format"
      }
    },
    "intentVocabulary": {
      "description": "Local agents express actions as intents — the in-process infrastructure resolves them against the symbol table, Oracle, and compiler APIs. Never generate shell commands.",
      "coreIntents": ["compile", "read-file", "write-file", "edit-file", "search", "ask-oracle", "type-help", "run-tests"],
      "discoveryIntents": ["find-definition", "find-references", "list-methods", "list-operators", "list-constructors", "list-properties", "get-type", "get-signature", "type-hierarchy", "find-implementations", "list-subtypes", "list-module-symbols", "list-modules", "method-resolution"],
      "criticalRule": "Discovery intents resolve from the in-process symbol table in ~0.01ms with zero I/O. ALWAYS prefer discovery intents over search for structural queries (finding definitions, listing methods, tracing hierarchies). The symbol table has this information indexed and typed — it cannot produce false positives.",
      "protocolQuery": "ek9 -qp intent vocabulary"
    }
  },

  "bootstrapSequence": {
    "description": "What both frontier and local LLMs should do when starting an ek9 -ai session",
    "steps": [
      {
        "step": 1,
        "action": "Load this forAI.json reference",
        "purpose": "Understand EK9's excluded features, tri-state semantics, closed types, quality metrics, and operator semantics"
      },
      {
        "step": 2,
        "action": "Know the Oracle exists and how to query it",
        "purpose": "565+ Q&A entries with compiler-validated code snippets are available via ask-oracle intent or ek9 -q. Always consult before coding."
      },
      {
        "step": 3,
        "action": "Know the intent vocabulary",
        "purpose": "22 intents available — 8 core + 14 discovery. Discovery intents use the in-process symbol table (~0.01ms). Never fork to shell for structural queries."
      },
      {
        "step": 4,
        "action": "Know the delegation protocol",
        "purpose": "Frontier delegates via structured briefs, local agents respond with compressed findings. Escalation when stuck. Protocol Q&A available via ek9 -qp."
      },
      {
        "step": 5,
        "action": "Know the compiler is in-process",
        "purpose": "Compilation is a Java method call (~80ms), not fork+exec (~2000ms). The JVM is warm, bootstrap is cached. Re-compile freely — it costs nothing."
      }
    ],
    "forFrontierLLM": "You coordinate. Delegate investigation and routine implementation to local agents. Retain architectural reasoning and novel design. Set terrain context in delegation briefs.",
    "forLocalLLM": "You execute. Consult the Oracle before coding. Use discovery intents for structural queries. Stay within response budgets. Escalate when stuck — do not guess.",
    "inProcessAdvantage": "The EK9 compiler runs in the same JVM. Symbol table queries cost ~0.01ms. Oracle queries cost ~3ms. Compilation costs ~80ms. There is no fork/exec, no JVM cold start, no stderr parsing. Everything is structured JSON from typed APIs."
  },

  "aiWorkflowGuidance": {
    "description": "Guidance for AI assistants to produce better EK9 code",
    "planFirst": {
      "description": "Always create a plan before writing EK9 code",
      "rule": "Present the plan to the user and ask for feedback before implementing",
      "questionsToAsk": [
        "Do you want standalone functions, or a trait/class design with operators?",
        "Should I use 'default operator' for auto-generated $, $$, :=:, <=> operators (==, <> and the other comparisons are generated from <=>)?",
        "Do you need a component/application (DI) architecture, or a simpler program?",
        "Should records use 'default operator $$' for JSON serialization?"
      ]
    },
    "designPatternSelection": {
      "description": "Choose the right EK9 pattern for the task",
      "patterns": [
        {
          "name": "Functions only",
          "when": "Simple utilities, stateless transformations, scripts",
          "example": "String formatting, math operations, data transformation"
        },
        {
          "name": "Trait + Class",
          "when": "CRUD operations, stateful services, polymorphic behavior",
          "example": "Database access, customer management, repository pattern",
          "rule": "If you define a trait, you MUST implement it with a class - never abandon a trait for standalone functions"
        },
        {
          "name": "Component + Application",
          "when": "Dependency injection, service wiring, enterprise architecture",
          "example": "Web applications, microservices, multi-component systems"
        },
        {
          "name": "Record + default operators",
          "when": "Data transfer objects, API responses, configuration, value objects",
          "example": "Customer record, OrderLine, Config",
          "rule": "Always consider 'default operator $$' for JSON and 'default operator $' for string display"
        }
      ]
    },
    "operatorAwareness": {
      "description": "EK9 records and classes can have operators - don't write functions for what operators provide",
      "criticalRule": "Before writing a function that converts to JSON or String, check if 'default operator $$' or 'default operator $' already does this",
      "autoGeneratedOperators": {
        "$$": "JSON serialization - produces JSON for all fields automatically",
        "$": "String representation - produces display string for all fields",
        "?": "isSet check - returns true only if ALL fields are set (and the super is set)",
        ":=:": "Shallow copy - each field of the target refers to the same object as the source's; write operator :=: yourself for a deep or selective copy",
        "==": "Equality comparison",
        "<=>": "Three-way comparison",
        "#?": "Hash code"
      },
      "example": {
        "wrong": "customerToJSON()\n  -> c as Customer\n  <- rtn as String: `{ \"name\": \"${c.name}\" }`",
        "correct": "//On the Customer record, add:\ndefault operator $$\n//Then use: $$customer or $$(listOfCustomers)"
      }
    },
    "traitImplementation": {
      "description": "Traits define interfaces - they must be implemented",
      "criticalRule": "If you define a trait, you MUST create a class 'with trait of' that implements it. Never define a trait and then use standalone functions instead.",
      "example": {
        "wrong": "defines trait\n  CustomerAccess\n    operator +=\n      -> customer as Customer\n\ndefines function\n  addCustomer()  //WRONG: standalone function instead of trait impl\n    ->\n      customers as List of Customer\n      customer as Customer",
        "correct": "defines trait\n  CustomerAccess\n    operator +=\n      -> customer as Customer\n\ndefines class\n  CustomerStore with trait of CustomerAccess\n    customers as List of Customer: List()\n\n    override operator +=\n      -> customer as Customer\n      customers += customer\n\n    default operator ?"
      }
    },
    "proactiveDiWorkflow": {
      "description": "Before adding or modifying dependency injection, inspect the current DI landscape to avoid compile errors",
      "when": "Any task involving: adding injection fields, registering components, wiring applications, adding aspects",
      "steps": [
        {
          "step": 1,
          "action": "Run 'ek9 -di -E3 main.ek9' to see the current wiring map",
          "purpose": "Understand existing registrations, their order, injection sites, and aspect proxies"
        },
        {
          "step": 2,
          "action": "Check if an application block exists",
          "purpose": "If no application exists, you must create one — adding injection fields alone will fail"
        },
        {
          "step": 3,
          "action": "Count existing injection fields on the target component",
          "purpose": "Components with 5+ injection fields trigger E11040 (excessive coupling) — use a facade instead"
        },
        {
          "step": 4,
          "action": "Identify where to insert new registrations in the ordering",
          "purpose": "Dependencies must be registered BEFORE dependents — E08200 fires if order is wrong"
        },
        {
          "step": 5,
          "action": "Add 'default operator ?' to any component with fields",
          "purpose": "Components with properties require operator ? for set/unset semantics — E07235 fires if missing"
        }
      ],
      "commonErrors": {
        "E07235": "Component has fields but no 'default operator ?' — add it after methods",
        "E07236": "Dynamic class captures variables as fields — add 'default operator ?' at end of body",
        "E08190": "Circular dependency — extract shared logic into a third component",
        "E08200": "Registration ordering — reorder so dependencies come first",
        "E08210": "Missing registration — add registration for the injected abstract type",
        "E11040": "Too many injection fields — split into smaller components or use a facade"
      },
      "errorLookup": "Use 'ek9 -h Exxxx' for full diagnosis, fix actions, and examples for any error code"
    },
    "errorDiagnosis": {
      "description": "When a compiler error occurs, use the built-in tools to understand and fix it",
      "steps": [
        "Read the error code (e.g., E50001) from the compiler output",
        "Run 'ek9 -h E50001' for full diagnosis with fix actions and examples",
        "For DI-related errors (E08xxx, E11xxx), also run 'ek9 -di -E3' for the wiring map",
        "Use 'ek9 -q <description>' to find related Q&A entries"
      ],
      "aiNote": "The 'ek9 -h Exxxx' output is structured as [DIAGNOSIS], [ACTION], [SEE ALSO] — designed for AI parsing"
    }
  },

  "inlineExamples": {
    "description": "Self-contained EK9 code examples for AI bootstrapping. These examples are complete and verified to compile.",
    "usage": "AI assistants can use these examples directly to understand EK9 syntax and patterns without external file access.",
    "reminder": "Use 'ek9 -h <keyword>' for help on topics, 'ek9 -h Exxxx' for error diagnosis, 'ek9 -di -E3' for DI wiring map, 'ek9 -q <words>' for Q&A lookup.",

    "helloWorld": {
      "pattern": "basic-program-structure",
      "description": "The canonical Hello World - minimal EK9 program structure",
      "keywords": ["program", "module", "stdout", "println", "<-"],
      "code": "#!ek9\ndefines module introduction\n\n  defines program\n\n    HelloWorld()\n      //Stdout is a built-in type - no import required\n      //The <- operator: declares 'stdout' AND assigns the new Stdout instance\n      //Type inference: compiler knows stdout is type Stdout\n      stdout <- Stdout()\n      stdout.println(\"Hello, World\")\n\n//EOF"
    },

    "simpleFunction": {
      "pattern": "function-with-parameters",
      "description": "Function with parameters and return value - shows -> for input, <- for output",
      "keywords": ["function", "->", "<-", "pure"],
      "code": "#!ek9\ndefines module example.functions\n\n  defines function\n\n    //Single parameter, single return\n    greet() as pure\n      -> name as String\n      <- message as String: \"Hello, \" + name\n\n    //Multiple parameters - use indented block after single ->\n    add() as pure\n      ->\n        a as Integer\n        b as Integer\n      <- result as Integer: a + b\n\n  defines program\n\n    Demo()\n      stdout <- Stdout()\n      stdout.println(greet(\"World\"))\n      stdout.println(`Sum: ${add(2, 3)}`)\n\n//EOF"
    },

    "simpleClass": {
      "pattern": "basic-class-structure",
      "description": "Class with properties, constructor, methods, and operator overloading",
      "keywords": ["class", "method", "property", "operator", "$"],
      "code": "#!ek9\ndefines module example.classes\n\n  defines class\n\n    Person\n      //Properties are always private\n      firstName <- String()\n      lastName <- String()\n\n      //Constructor\n      Person()\n        ->\n          firstName as String\n          lastName as String\n        this.firstName :=: firstName\n        this.lastName :=: lastName\n\n      //Method\n      fullName() as pure\n        <- rtn as String: `${firstName} ${lastName}`\n\n      //Operator $ for string conversion\n      operator $ as pure\n        <- rtn as String: fullName()\n\n      //Operator ? for isSet check\n      default operator ?\n\n  defines program\n\n    Demo()\n      stdout <- Stdout()\n      person <- Person(\"Steve\", \"Limb\")\n      stdout.println($person)\n\n//EOF"
    },

    "classExtension": {
      "pattern": "class-extension-hierarchy",
      "description": "Abstract and open classes - EK9 types are closed by default",
      "keywords": ["extends", "override", "abstract", "open"],
      "code": "#!ek9\ndefines module example.inheritance\n\n  defines class\n\n    //Abstract classes are automatically open\n    Shape as abstract\n      name <- String()\n\n      Shape()\n        -> name as String\n        this.name :=? name\n\n      area() as pure abstract\n        <- rtn as Float?\n\n      operator $ as pure\n        <- rtn as String: name ?: \"Unknown\"\n\n      default operator ?\n\n    //Concrete class extending abstract - closed by default\n    Circle extends Shape\n      radius <- Float()\n\n      Circle()\n        -> radius as Float\n        super(\"Circle\")\n        this.radius :=? radius\n\n      override area() as pure\n        <- rtn as Float: 3.14159 * radius * radius\n\n      default operator ?\n      default operator $\n\n    //Concrete but marked 'as open' for extension\n    Rectangle extends Shape as open\n      width <- Float()\n      height <- Float()\n\n      Rectangle()\n        ->\n          width as Float\n          height as Float\n        super(\"Rectangle\")\n        this.width :=? width\n        this.height :=? height\n\n      override area() as pure\n        <- rtn as Float: width * height\n\n      default operator ?\n      default operator $\n\n    //Can extend Rectangle because it's 'as open'\n    Square extends Rectangle\n      Square()\n        -> side as Float\n        super(side, side)\n\n  defines program\n\n    Demo()\n      stdout <- Stdout()\n      shapes <- [Circle(5.0), Rectangle(4.0, 3.0), Square(2.0)]\n      for shape in shapes\n        stdout.println(`${shape}: area = ${shape.area()}`)\n\n//EOF"
    },

    "abstractFunction": {
      "pattern": "abstract-function-polymorphism",
      "description": "Abstract functions as interfaces for polymorphic behavior",
      "keywords": ["function", "abstract", "pure", "is"],
      "code": "#!ek9\ndefines module example.polymorphism\n\n  defines function\n\n    //Abstract function - defines interface\n    mathOperation() as pure abstract\n      ->\n        x as Float\n        y as Float\n      <- result as Float?\n\n    //Concrete implementations\n    add() is mathOperation as pure\n      ->\n        x as Float\n        y as Float\n      <- result as Float: x + y\n\n    subtract() is mathOperation as pure\n      ->\n        x as Float\n        y as Float\n      <- result as Float: x - y\n\n    multiply() is mathOperation as pure\n      ->\n        x as Float\n        y as Float\n      <- result as Float: x * y\n\n  defines program\n\n    Demo()\n      stdout <- Stdout()\n      //Functions can be stored and called polymorphically\n      for op in [add, subtract, multiply]\n        stdout.println(`Result: ${op(10.0, 5.0)}`)\n\n//EOF"
    },

    "traitComposition": {
      "pattern": "trait-with-delegation",
      "description": "Traits for composition, delegation with 'by', and 'allow only' restriction",
      "keywords": ["trait", "with", "by", "delegate", "allow only"],
      "code": "#!ek9\ndefines module example.traits\n\n  defines trait\n\n    //Simple trait\n    Printable\n      print() abstract\n        <- rtn as String?\n\n    //Trait inheriting from another\n    Loggable with trait of Printable\n      log() abstract\n        <- rtn as String?\n\n    //Trait with 'allow only' restriction\n    SecureData allow only EncryptedMessage, SignedMessage\n      data() abstract\n        <- rtn as String?\n\n  defines class\n\n    //Class implementing trait\n    Message with trait of Printable\n      content <- String()\n\n      Message()\n        -> content as String\n        this.content :=? content\n\n      override print()\n        <- rtn as String: content\n\n      default operator ?\n\n    //Only these can implement SecureData\n    EncryptedMessage with trait of SecureData\n      override data()\n        <- rtn as String: \"[encrypted]\"\n\n    SignedMessage with trait of SecureData\n      override data()\n        <- rtn as String: \"[signed]\"\n\n    //Class implementing a trait that inherits another: log() and the inherited print()\n    LoggingMessage with trait of Loggable\n      message as Printable: Message(\"default\")\n\n      LoggingMessage()\n        -> message as Printable\n        this.message: message\n\n      override print()\n        <- rtn as String: message.print()\n\n      override log()\n        <- rtn as String: `[LOG] ${print()}`\n\n      default operator ?\n\n    //Delegation with 'by' - every Printable method is answered by 'printer'\n    ProxyMessage with trait of Printable by printer\n      printer as Printable: Message(\"default\")\n\n      ProxyMessage()\n        -> printer as Printable\n        this.printer: printer\n\n      default operator ?\n\n  defines program\n\n    Demo()\n      stdout <- Stdout()\n      msg <- LoggingMessage(Message(\"Hello\"))\n      stdout.println(msg.log())\n      proxy <- ProxyMessage(Message(\"Delegated\"))\n      stdout.println(proxy.print())\n\n//EOF"
    },

    "enumeration": {
      "pattern": "enumeration-with-operators",
      "description": "Enumerations with built-in operators, iteration, and switch integration. CRITICAL: Enumerations automatically get 24 operators from a simple value list declaration - no 'default operator' directives needed. Do NOT write comparison, conversion, lookup, or serialization functions for enumerations - they are all built-in.",
      "keywords": ["type", "enum", "for", "switch", "cat"],
      "aiWarning": "EK9 enumerations are NOT like Java/Python/C# enums. From just a value list (e.g., Colour with Red, Green, Blue), you get 24 operators automatically. Do NOT write: compareEnums() (use < > <= >= <=>), enumToString() (use $), enumToJson() (use $$), findByName() (use Colour(name)), getFirst/getLast() (use #< #>), isValid() (use Colour(name)?), getAllValues() (use cat Colour | collect). ALL of these are built-in.",
      "automaticOperators": {
        "sameTypeComparison": {
          "operators": ["==", "<>", "<", ">", "<=", ">=", "<=>"],
          "description": "Compare two enum values by declaration order (ordinal). Red < Blue is true if Red declared before Blue.",
          "count": 7
        },
        "stringParamComparison": {
          "operators": ["==", "<>", "<", ">", "<=", ">=", "<=>"],
          "description": "Compare enum to a String directly. colour == \"Red\" works without conversion.",
          "count": 7
        },
        "stringConversion": {
          "operators": ["$", "#^"],
          "description": "$ returns the value name as String. #^ promotes to String (same result for enums).",
          "count": 2
        },
        "jsonSerialization": {
          "operators": ["$$"],
          "description": "$$ returns JSON representation of the enum value name.",
          "count": 1
        },
        "hashCode": {
          "operators": ["#?"],
          "description": "Ordinal-based hash code, suitable for Dict keys.",
          "count": 1
        },
        "isSet": {
          "operators": ["?"],
          "description": "Tri-state check. Colour() is unset, Colour.Red is set.",
          "count": 1
        },
        "firstLast": {
          "operators": ["#<", "#>"],
          "description": "#< returns first declared value, #> returns last declared value.",
          "count": 2
        },
        "constructors": {
          "signatures": ["Colour()", "Colour(Colour)", "Colour(String)"],
          "description": "Default (creates unset), copy, and construct-from-string (unset if no match).",
          "count": 3
        },
        "totalAutoGenerated": 24
      },
      "code": "#!ek9\ndefines module example.enumerations\n\n  defines type\n\n    CardSuit\n      Hearts\n      Diamonds\n      Clubs\n      Spades\n\n    CardRank\n      Two\n      Three\n      Four\n      Five\n      Six\n      Seven\n      Eight\n      Nine\n      Ten\n      Jack\n      Queen\n      King\n      Ace\n\n  defines program\n\n    Demo()\n      stdout <- Stdout()\n\n      //Access enum values\n      hearts <- CardSuit.Hearts\n      clubs <- CardSuit.Clubs\n\n      //Comparison operators - ALL built-in, do NOT write comparison functions\n      stdout.println(`hearts < clubs: ${hearts < clubs}`)\n      stdout.println(`hearts == clubs: ${hearts == clubs}`)\n      stdout.println(`hearts <=> clubs: ${hearts <=> clubs}`)\n\n      //String-param comparison - compare directly to String\n      stdout.println(`hearts == Hearts: ${hearts == \"Hearts\"}`)\n\n      //String conversion ($) and JSON ($$) - do NOT write toString/toJson\n      stdout.println(`Suit: ${$hearts}`)\n      stdout.println(`JSON: ${$$hearts}`)\n\n      //Hash code (#?) - do NOT write hashCode functions\n      stdout.println(`Hash: ${#?hearts}`)\n\n      //First (#<) and Last (#>) of any value's enumeration - do NOT write getFirst/getLast\n      stdout.println(`First: ${#< hearts}`)\n      stdout.println(`Last: ${#> hearts}`)\n\n      //Construct from string - do NOT write findByName functions\n      validSuit <- CardSuit(\"Clubs\")\n      require validSuit?\n\n      invalidSuit <- CardSuit(\"Invalid\")\n      require ~invalidSuit?\n\n      //Is-set check - do NOT write isValid functions\n      require hearts?\n      unknownSuit <- CardSuit()\n      require ~unknownSuit?\n\n      //Iterate all enum values - do NOT write getAllValues\n      stdout.println(\"All suits:\")\n      for suit in CardSuit\n        stdout.println($suit)\n\n      //Switch on enum\n      for rank in CardRank\n        message <- switch rank\n          <- rtn as String?\n          case CardRank.Ace\n            rtn: `Wow, an ${rank}!`\n          case > CardRank.Ten\n            rtn: `Face card: ${rank}`\n          default\n            rtn: `Number: ${rank}`\n        stdout.println(message)\n\n      //Stream pipeline with enum\n      suits <- cat CardSuit | collect as List of CardSuit\n      require suits?\n\n//EOF"
    },

    "constants": {
      "pattern": "constant-declarations",
      "description": "Native literal types for constants - all built-in types supported",
      "keywords": ["constant", "literal", "Integer", "Float", "Duration", "Date"],
      "code": "#!ek9\ndefines module example.constants\n\n  defines constant\n\n    //Boolean literals\n    limitRetries <- true\n    updateLog <- false\n\n    //Character and String\n    delimiter <- ':'\n    author <- \"Steve Limb\"\n\n    //Numbers\n    maxRetries <- 10\n    minTemp <- -2\n    Pi <- 3.14159\n    bitMask <- 0b01110001\n\n    //Time literals\n    noon <- 12:00\n    justAfterNoon <- 12:00:01\n\n    //Duration literals (ISO 8601)\n    maxDuration <- P3Y2M6DT12H15M6S\n    twoYears <- P2Y\n    twoHours <- PT2H\n    timeout <- 250ms\n\n    //Date and DateTime\n    millennium <- 2000-01-01\n    created <- 2018-01-31T01:30:00-05:00\n\n    //Money and Colour\n    maxPayment <- 300000#USD\n    defaultColour <- #AB6F2B\n\n    //Dimension\n    twoMeters <- 2m\n\n    //RegEx\n    matchSteves <- /[S|s]te(?:ven?|phen)/\n\n//EOF"
    },

    "ifStatement": {
      "pattern": "if-statement-comprehensive",
      "description": "If statements with guards, declarations, and range checks",
      "keywords": ["if", "else", "when", "guard", "<-", ":="],
      "code": "#!ek9\ndefines module example.flowcontrol\n\n  defines function\n\n    getTemperature()\n      -> country as String\n      <- temperature <- Integer()\n      if country == \"GB\"\n        temperature :=? 20\n      else if country == \"US\"\n        temperature :=? 75\n\n    getScore()\n      <- rtn as Integer: 9\n\n  defines program\n\n    Demo()\n      stdout <- Stdout()\n\n      //Simple if\n      score <- getScore()\n      limit <- 10\n      if score < limit\n        stdout.println(\"Less than 10\")\n\n      //If-else chain\n      target <- 9\n      result <- String()\n      if score > target\n        result: \"Too High\"\n      else if score < target\n        result: \"Too Low\"\n      else\n        result: \"Just Right\"\n      stdout.println(result)\n\n      //'when' is synonym for 'if'\n      when score < limit\n        stdout.println(\"Still less than 10\")\n\n      //Guard with declaration - variable scoped to if block\n      //Block only executes if getTemperature returns SET value\n      when reading <- getTemperature(\"GB\") with reading > limit\n        stdout.println(`UK temp: ${reading}`)\n\n      //Re-point an existing variable, check it is set, then the condition\n      hot <- 50\n      existingTemp <- Integer()\n      if existingTemp := getTemperature(\"US\") then existingTemp? and (existingTemp > hot)\n        stdout.println(`US is hot: ${existingTemp}`)\n\n      //Range check - literals in a range need names too\n      x <- 15\n      upper <- 20\n      if x in limit ... upper\n        stdout.println(\"x is between 10 and 20\")\n\n      small <- 5\n      if x not in 1 ... small\n        stdout.println(\"x is not between 1 and 5\")\n\n//EOF"
    },

    "switchStatement": {
      "pattern": "switch-statement-comprehensive",
      "description": "Switch with case, expressions, comparison operators, and guards - NO fallthrough",
      "keywords": ["switch", "given", "case", "when", "default"],
      "code": "#!ek9\ndefines module example.switch\n\n  defines type\n\n    Status\n      Active\n      Pending\n      Closed\n\n  defines function\n\n    getCurrentTemp()\n      <- rtn <- 20\n\n    getScore()\n      <- rtn <- 25\n\n  defines program\n\n    Demo()\n      stdout <- Stdout()\n\n      //'switch' and 'given' are synonyms\n      //'case' and 'when' are synonyms\n      //NO fallthrough - each case is independent (by design)\n\n      //Basic switch\n      status <- Status.Active\n      switch status\n        case Status.Active\n          stdout.println(\"Processing...\")\n        case Status.Pending\n          stdout.println(\"Waiting...\")\n        case Status.Closed\n          stdout.println(\"Done\")\n        default\n          stdout.println(\"Unknown\")\n\n      //Switch as expression - returns a value\n      score <- getScore()\n      result <- given score\n        <- rtn as String?\n        when < 10\n          rtn: \"Low\"\n        when 20, 21, 22, 23, 24\n          rtn: \"Perfect\"\n        when > 30\n          rtn: \"High\"\n        default\n          rtn: \"OK\"\n      stdout.println(`Result: ${result}`)\n\n      //Multiple values in one case (replaces fallthrough)\n      day <- 3\n      dayType <- switch day\n        <- rtn as String?\n        case 1, 7\n          rtn: \"Weekend\"\n        case 2, 3, 4, 5, 6\n          rtn: \"Weekday\"\n        default\n          rtn: \"Unknown\"\n      stdout.println(`Day type: ${dayType}`)\n\n      //Switch with comparison operators\n      multiplier <- 5\n      category <- switch score\n        <- rtn as String?\n        case < 12\n          rtn: \"Moderate\"\n        case > 10*multiplier\n          rtn: \"Very High\"\n        case getCurrentTemp(), 21, 22\n          rtn: \"Perfect\"\n        default\n          rtn: \"Suitable\"\n      stdout.println(`Category: ${category}`)\n\n      //Switch with declaration guard\n      //The body runs only when the guard is set, so the result needs a value for when it is not\n      text <- switch reading <- getCurrentTemp() with reading\n        <- rtn as String: \"No reading\"\n        case < 15\n          rtn: `Cold: ${reading}`\n        case > 25\n          rtn: `Hot: ${reading}`\n        default\n          rtn: `Nice: ${reading}`\n\n      stdout.println(text)\n\n//EOF"
    },

    "forLoop": {
      "pattern": "for-loop-comprehensive",
      "description": "For loops with ranges, collections, iterators - NO break/continue",
      "keywords": ["for", "in", "by", "range", "..."],
      "code": "#!ek9\ndefines module example.forloop\n\n  defines program\n\n    Demo()\n      stdout <- Stdout()\n\n      //Range iteration (inclusive)\n      stdout.println(\"1 to 5:\")\n      for i in 1 ... 5\n        stdout.println($i)\n\n      //Range with step\n      stdout.println(\"1 to 10 by 2:\")\n      for i in 1 ... 10 by 2\n        stdout.println($i)\n\n      //Descending range\n      stdout.println(\"10 down to 1:\")\n      for i in 10 ... 1 by -1\n        stdout.println($i)\n\n      //Collection iteration\n      items <- [\"Alpha\", \"Beta\", \"Charlie\"]\n      for item in items\n        stdout.println(item)\n\n      //String iteration (characters)\n      for char in \"Hello\"\n        stdout.println(char)\n\n      //Iterator directly\n      iter <- items.iterator()\n      for item in iter\n        stdout.println(`Via iterator: ${item}`)\n\n      //Float range\n      for f in 1.0 ... 5.0 by 0.5\n        stdout.println($f)\n\n      //Time range\n      start <- 09:00\n      finish <- 17:00\n      for t in start ... finish by PT1H\n        stdout.println($t)\n\n      //NO break/continue in EK9!\n      //Use streams instead:\n      //cat items | filter by predicate | head\n\n//EOF"
    },

    "whileLoop": {
      "pattern": "while-loop-comprehensive",
      "description": "While and do-while loops with guards and as expressions",
      "keywords": ["while", "do", "with", "then"],
      "code": "#!ek9\ndefines module example.whileloop\n\n  defines program\n\n    Demo()\n      stdout <- Stdout()\n\n      //Basic while\n      items <- ['A', 'B', 'C']\n      iter <- items.iterator()\n      while iter.hasNext()\n        item <- iter.next()\n        stdout.println(item)\n\n      //While re-pointing an existing variable - ALWAYS assigns a fresh iterator; the check runs every pass\n      while iter := items.iterator() then iter? and iter.hasNext()\n        item <- iter.next()\n        stdout.println(`Again: ${item}`)\n\n      //While with declaration - variable scoped to loop\n      while newIter <- items.iterator() then newIter.hasNext()\n        item <- newIter.next()\n        stdout.println(`New: ${item}`)\n\n      //Do-while - body executes at least once\n      resetIter <- items.iterator()\n      if resetIter.hasNext()\n        do\n          item <- resetIter.next()\n          stdout.println(`Do: ${item}`)\n        while resetIter.hasNext()\n\n      //While as expression - returns value\n      loops <- 10\n      result <- while complete <- false with not complete\n        <- rtn <- 0\n        rtn++\n        complete: rtn == loops\n      stdout.println(`While result: ${result}`)\n\n      //Do-while as expression\n      fewerLoops <- 5\n      result2 <- do complete <- false\n        <- rtn <- 0\n        rtn++\n        complete: rtn == fewerLoops\n      while not complete\n      stdout.println(`Do result: ${result2}`)\n\n//EOF"
    },

    "tryCatch": {
      "pattern": "exception-handling-comprehensive",
      "description": "Try/catch/finally with guards, custom exceptions, and dispatcher pattern",
      "keywords": ["try", "catch", "handle", "finally", "throw", "Exception"],
      "code": "#!ek9\ndefines module example.exceptions\n\n  defines constant\n\n    maxNumber <- 100\n\n  defines class\n\n    //Custom exception with additional field\n    ValidationException extends Exception\n      fieldName <- String()\n\n      ValidationException()\n        ->\n          message as String\n          fieldName as String\n        super(message, 1)\n        this.fieldName :=? fieldName\n\n      fieldName() as pure\n        <- rtn as String: fieldName\n\n      override operator $ as pure\n        <- rtn as String: `${reason()} [field: ${fieldName}]`\n\n      default operator ?\n      default operator $$\n\n    Processor\n\n      process()\n        -> number as Integer\n        <- rtn as String: String()\n\n        if number < 0\n          throw ValidationException(\"Negative not allowed\", \"number\")\n        else if number > maxNumber\n          throw Exception(\"Too large\", 2)\n        else\n          rtn: `Processed: ${number}`\n\n      //Dispatcher for type-specific exception handling\n      handleError() as dispatcher\n        -> ex as Exception\n        <- rtn as String: $ex\n\n      handleError()\n        -> ex as ValidationException\n        <- rtn as String: `Validation failed: ${ex.fieldName()}`\n\n  defines program\n\n    Demo()\n      stdout <- Stdout()\n      stderr <- Stderr()\n      processor <- Processor()\n\n      for number in [-1, 50, 150]\n        try\n          result <- processor.process(number)\n          stdout.println(result)\n        catch\n          -> ex as Exception\n          //Dispatcher routes to specific handler\n          stderr.println(processor.handleError(ex))\n        finally\n          stdout.println(`Finished processing ${number}`)\n\n      //Try with resource auto-close\n      try\n        -> input <- TextFile(\"test.txt\").input()\n        cat input > stdout\n      handle\n        -> ex as Exception\n        stderr.println($ex)\n      finally\n        stdout.println(\"File auto-closed\")\n\n//EOF"
    },

    "streams": {
      "pattern": "stream-pipelines",
      "description": "Stream pipelines replace loops with break/continue - cat, filter, map, head, collect",
      "keywords": ["cat", "|", "filter", "map", "head", "tail", "collect", ">"],
      "code": "#!ek9\ndefines module example.streams\n\n  defines function\n\n    isEven() as pure\n      -> n as Integer\n      <- rtn as Boolean: n mod 2 == 0\n\n    double() as pure\n      -> n as Integer\n      <- rtn as Integer: n * 2\n\n    formatItem() as pure\n      -> n as Integer\n      <- rtn as String: `Item: ${n}`\n\n    joinWithComma() as pure\n      ->\n        a as String\n        b as String\n      <- rtn as String: a? and b? <- `${a}, ${b}` : String()\n\n  defines program\n\n    Demo()\n      stdout <- Stdout()\n      numbers <- [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\n\n      //Output directly to stdout\n      stdout.println(\"All numbers:\")\n      cat numbers > stdout\n\n      //Filter - replaces continue pattern\n      stdout.println(\"Even numbers:\")\n      cat numbers | filter by isEven > stdout\n\n      //Map - transform each item\n      stdout.println(\"Doubled:\")\n      cat numbers | map by double > stdout\n\n      //Head - replaces break pattern (take first N)\n      stdout.println(\"First 3:\")\n      cat numbers | head 3 > stdout\n\n      //Tail - last N items\n      stdout.println(\"Last 3:\")\n      cat numbers | tail 3 > stdout\n\n      //Skip - skip first N\n      stdout.println(\"Skip first 5:\")\n      cat numbers | skip 5 > stdout\n\n      //Chain multiple operations\n      stdout.println(\"Even, doubled, first 3:\")\n      cat numbers | filter by isEven | map by double | head 3 > stdout\n\n      //Collect into List\n      evens <- cat numbers | filter by isEven | collect as List of Integer\n      stdout.println(`Collected evens: ${evens}`)\n\n      //Collect into String with join\n      formatted <- cat numbers\n        | map by formatItem\n        | join with joinWithComma\n        | collect as String\n      stdout.println(`Joined: ${formatted}`)\n\n      //Range as stream source\n      stdout.println(\"Range stream:\")\n      for i in 1 ... 5 | map by double > stdout\n\n//EOF"
    },

    "generics": {
      "pattern": "generic-types",
      "description": "Generic/parameterized types - List of T, Optional of T, custom generics",
      "keywords": ["of", "List", "Dict", "Optional", "generic", "constrain"],
      "code": "#!ek9\ndefines module example.generics\n\n  defines function\n\n    //Generic function\n    identity() of type T\n      -> item as T\n      <- rtn as T: item\n\n    //Generic over any T that has a > operator - checked when it is parameterised\n    findMax() of type T\n      ->\n        a as T\n        b as T\n      <- rtn as T: a > b <- a else b\n\n  defines class\n\n    //Generic class\n    Container of type T\n      item as T?\n\n      Container()\n        item :=? T()\n\n      Container()\n        -> item as T\n        this.item :=? item\n\n      get() as pure\n        <- rtn as T: item\n\n      set()\n        -> newItem as T\n        item :=: newItem\n\n      override operator ? as pure\n        <- rtn as Boolean: item?\n\n  defines program\n\n    Demo()\n      stdout <- Stdout()\n\n      //Built-in generic types\n      strings <- List() of String\n      strings += \"Hello\"\n      strings += \"World\"\n      stdout.println(`List: ${strings}`)\n\n      //Dict (key-value)\n      ages <- Dict() of (String, Integer)\n      ages += DictEntry(\"Steve\", 30)\n      ages += DictEntry(\"John\", 25)\n      stdout.println(`Dict: ${ages}`)\n\n      //Optional\n      maybeValue <- Optional(42)\n      if maybeValue?\n        stdout.println(`Optional has: ${maybeValue.get()}`)\n\n      noValue <- Optional() of String\n      stdout.println(`Empty optional is set: ${noValue?}`)\n\n      //Custom generic\n      container <- Container(\"test\")\n      stdout.println(`Container: ${container.get()}`)\n\n      //Generic functions\n      result <- identity(\"Hello\")\n      stdout.println(`Identity: ${result}`)\n\n      //Two T parameters cannot infer T: parameterise first, then call\n      maxOfIntegers <- findMax() of Integer\n      max <- maxOfIntegers(10, 20)\n      stdout.println(`Max: ${max}`)\n\n//EOF"
    },

    "dynamicFunctions": {
      "pattern": "dynamic-functions-and-closures",
      "description": "Dynamic functions with capture - EK9's approach to closures/lambdas. Syntax: '(captures) is/extends AbstractFn as function'. For generic functions: '() extends Function of (In, Out) as pure function'. 'as function' is required on the first alternative or when extending parameterised generic functions. Capture can be unnamed '(threshold)' or named '(lo: minValue)'. Single-line form: '(capture) is fn as pure (rtn: expr)'. CAPTURE SEMANTICS: captures hold the pointer value at capture time — each closure has its own pointer slot, so outer pointer rebinding ('outer := newValue') does NOT affect the closure's captured value. BUT mutating the captured object via '+=', ':=:', ':~:', etc. mutates the SHARED object visible to the caller. For an isolated snapshot, copy via ':=:' or construct a new instance via the type's copy constructor BEFORE capture. Note: 'default operator :=:' is a SHALLOW copy - each field of the copy refers to the same object, so it is no snapshot of mutable fields; write 'operator :=:' yourself for a deep or selective copy (ek9 -q deep or selective copy). See operators.html#copy_principle. Same issue Java has with reference types — EK9 makes the rebind-vs-copy distinction grammatical (':=' vs ':=:'). See QA1296 for capture isolation patterns.",
      "keywords": ["dynamic", "function", "capture", "is", "as function", "extends", "Predicate", "Function"],
      "code": "#!ek9\ndefines module example.dynamic\n\n  defines function\n\n    //Abstract function to implement\n    predicate() as pure abstract\n      -> number as Integer\n      <- rtn as Boolean?\n\n    transformer() as pure abstract\n      -> number as Integer\n      <- rtn as Integer?\n\n  defines program\n\n    Demo()\n      stdout <- Stdout()\n\n      threshold <- 10\n      multiplier <- 3\n\n      //Dynamic function capturing 'threshold' — 'as pure function' because predicate is pure\n      greaterThan <- (threshold) is predicate as pure function\n        rtn: number > threshold\n\n      //Dynamic function capturing 'multiplier'\n      multiply <- (multiplier) is transformer as pure function\n        rtn: number * multiplier\n\n      //Test the dynamic functions\n      for n in [5, 10, 15]\n        if greaterThan(n)\n          stdout.println(`${n} > ${threshold}: ${multiply(n)}`)\n\n      //Inline lambda-like syntax (single expression)\n      lessThan <- (threshold) is predicate as pure (rtn: number < threshold)\n\n      //Multiple captures with named parameters\n      inRange <- (lo: 5, hi: 15) is predicate as pure (rtn: number > lo and number < hi)\n\n      //Functions as values in list — including inRange\n      predicates <- [\n        (threshold) is predicate as pure (rtn: number == threshold),\n        greaterThan,\n        lessThan,\n        inRange\n        ]\n\n      for pred in predicates\n        stdout.println(`10 matches: ${pred(10)}`)\n\n      //Extending built-in generic functions (Predicate of T, Function of (In, Out))\n      theValues <- [1, 2, 3, 4, 5]\n\n      //Indented form with generic Predicate\n      odd <- () extends Predicate of Integer as pure function\n        r: t mod 2 == 0\n\n      //Single-line form with generic Function\n      asString <- () extends Function of (Integer, String) as pure function (r : $t)\n      asFloat <- () extends Function of (Integer, Float) as pure function (r : t)\n\n      captured <- List() of String\n      allAsFloat <- List() of Float\n\n      cat theValues\n        | tee by asFloat then in allAsFloat\n        | reject odd\n        | map with asString\n        | tee captured\n        > stdout\n\n//EOF"
    },

    "dynamicClasses": {
      "pattern": "dynamic-classes-and-traits",
      "description": "Dynamic classes with capture and trait composition. Three forms: (1) Trait-based: '(captures) trait of TraitName as class' or '() with trait of TraitName as class' — both forms valid; 'with' is a stylistic addition. (2) Tuple/named: 'TupleName(captures) as class' — creates a reusable type with methods and operators. (3) Generic extension: '() extends GenericClass of Type as class' — note 'extends' on a dynamic class works ONLY for generic parameterization ('of T'); it cannot extend a non-generic concrete class. For non-generic extension + traits combos, author a named top-level class instead. Dynamic classes generally end with 'default operator ?' (or explicit 'operator ?'); when extending a class that already provides a concrete 'operator ?', the dynamic class inherits it and need not redeclare. Multi-trait delegation: 'trait of T1 by impl1, T2 by impl2' delegates trait methods to captured implementations. CAPTURE SEMANTICS: captures hold the pointer value at capture time — each instance has its own pointer slots, so outer pointer rebinding does NOT affect captured fields. BUT mutating the captured object via '+=', ':=:', ':~:', etc. mutates the SHARED object visible to the caller. For an isolated snapshot, copy via ':=:' or copy constructor BEFORE capture. Note: 'default operator :=:' is a SHALLOW copy - each field of the copy refers to the same object, so it is no snapshot of mutable fields; write 'operator :=:' yourself for a deep or selective copy (ek9 -q deep or selective copy). See operators.html#copy_principle. Same issue as Java reference types — EK9 makes the rebind-vs-copy distinction grammatical (':=' vs ':=:'). See QA1296 for capture isolation patterns.",
      "keywords": ["dynamic", "class", "trait", "as class", "by", "capture", "tuple", "with trait of"],
      "code": "#!ek9\ndefines module example.dynamicclasses\n\n  defines trait\n\n    Describable\n      describe() abstract\n        <- rtn as String?\n\n    Printable\n      format() abstract\n        <- rtn as String?\n\n  defines class\n\n    //Generic abstract class for extension\n    Processor of type T as abstract\n      process() as abstract\n        -> item as T\n        <- rtn as String?\n\n      override operator ? as pure\n        <- rtn as Boolean: true\n\n  defines program\n\n    Demo()\n      stdout <- Stdout()\n\n      //--- Form 1: Trait-based dynamic class ---\n      //Simple trait implementation with capture\n      greeting <- \"Hello\"\n      greeter <- (greeting) with trait of Describable as class\n        override describe()\n          <- rtn as String: greeting\n        default operator ?\n\n      stdout.println(greeter.describe())\n\n      //Named capture (field name differs from source variable)\n      messageText <- \"Welcome\"\n      printer <- (msg: messageText) with trait of Printable as class\n        override format()\n          <- rtn as String: msg\n        default operator ?\n\n      stdout.println(printer.format())\n\n      //--- Multi-trait delegation with 'by' ---\n      //Compose traits by delegating to captured implementations\n      combo <- (greeter, printer) trait of Describable by greeter, Printable by printer\n        default operator ?\n\n      //combo.describe() delegates to greeter, combo.format() delegates to printer\n      stdout.println(combo.describe())\n      stdout.println(combo.format())\n\n      //--- Mixed: delegate some traits, implement others inline ---\n      mixed <- (printer) trait of Describable, Printable by printer\n        override describe()\n          <- rtn as String: `Mixed: ${format()}`\n        default operator ?\n\n      stdout.println(mixed.describe())\n\n      //--- Form 2: Tuple/named dynamic class ---\n      //Creates a reusable type 'PersonTuple' with methods and operators\n      personName <- \"Steve\"\n      born <- 1970-01-01\n      person <- PersonTuple(name: personName, dob: born) as class\n        personsName()\n          <- rtn as String: name\n        operator $ as pure\n          <- rtn as String: `${name} born ${dob}`\n        default operator ?\n\n      stdout.println($person)\n      stdout.println(person.personsName())\n\n      //Tuple type is reusable — can call constructors and use in functions\n      person2 <- PersonTuple(\"Jane\", 1985-06-15)\n      stdout.println($person2)\n\n      //--- Form 3: Generic extension dynamic class ---\n      //Extend a parameterised generic class inline\n      stringProcessor <- () extends Processor of String as class\n        override process()\n          -> item as String\n          <- rtn as String: `Processed: ${item}`\n\n      stdout.println(stringProcessor.process(\"data\"))\n\n//EOF"
    },

    "ternaryOperators": {
      "pattern": "ternary-and-coalescing",
      "description": "Ternary conditional, null coalescing, elvis, min/max selection operators",
      "keywords": ["<-", ":", "??", "?:", "<?", ">?"],
      "code": "#!ek9\ndefines module example.ternary\n\n  defines program\n\n    Demo()\n      stdout <- Stdout()\n\n      //Ternary conditional: condition <- trueValue : falseValue\n      x <- 15\n      threshold <- 10\n      result <- x > threshold <- \"big\" : \"small\"\n      stdout.println(`x is ${result}`)\n\n      //isSet check in condition\n      name <- String()\n      display <- name? <- name : \"Anonymous\"\n      stdout.println(`Display: ${display}`)\n\n      //Null coalescing ?? - returns left unless it is ABSENT; value1 is present but UNSET, so it passes through\n      value1 <- String()\n      value2 <- \"Default\"\n      coalesced <- value1 ?? value2\n      stdout.println(`Coalesced is set: ${coalesced?}`)\n\n      //Elvis ?: - returns left only if SET, so this is how to default an unset value\n      elvis <- value1 ?: value2\n      stdout.println(`Elvis: ${elvis}`)\n\n      //Min selection <? - return smaller value\n      a <- 5\n      b <- 10\n      minVal <- a <? b\n      stdout.println(`Min: ${minVal}`)\n\n      //Max selection >? - return larger value\n      maxVal <- a >? b\n      stdout.println(`Max: ${maxVal}`)\n\n      //Works with unset values - returns the SET one\n      unsetNum <- Integer()\n      setNum <- 42\n      selected <- unsetNum <? setNum\n      stdout.println(`Selected: ${selected}`)\n\n      //Chained ternary for complex selection\n      status <- 2\n      message <- status == 0 <- \"OK\" : status == 1 <- \"Warning\" : \"Error\"\n      stdout.println(`Status: ${message}`)\n\n//EOF"
    },

    "records": {
      "pattern": "record-with-operators",
      "description": "Records with operators: copy :=:, merge :~:, JSON $$, String $, comparison <=>. Records can have ALL operators (unlike structs in other languages). Use 'default operator' for auto-generation.",
      "keywords": ["record", ":=:", ":~:", "<~>", "<=>", "extends", "$$", "$", "default"],
      "code": "#!ek9\ndefines module example.records\n\n  defines type\n\n    //Constrained type\n    PositiveId as Integer constrain as\n      > 0\n\n  defines record\n\n    //Base record\n    IdRecord as abstract\n      id <- PositiveId()\n\n      IdRecord()\n        -> id as PositiveId\n        require id?\n        this.id :=? id\n\n      operator $ as pure\n        <- rtn as String: $id\n\n      override operator ? as pure\n        <- rtn as Boolean: id?\n\n    //Extended record with manual operators\n    Person extends IdRecord\n      firstName as String: String()\n      lastName as String: String()\n\n      Person()\n        ->\n          id as PositiveId\n          firstName as String\n          lastName as String\n        super(id)\n        this.firstName :=? firstName\n        this.lastName :=? lastName\n\n      //Copy operator - copy each field through its own :=:\n      operator :=:\n        -> other as Person\n        id :=: other.id\n        firstName :=: other.firstName\n        lastName :=: other.lastName\n\n      //Merge operator - only copy unset fields\n      operator :~:\n        -> other as Person\n        if not id?\n          id :=: other.id\n        if not firstName?\n          firstName :=: other.firstName\n        if not lastName?\n          lastName :=: other.lastName\n\n      //Fuzzy match - similarity score\n      operator <~> as pure\n        -> other as Person\n        <- rtn as Integer: (firstName <~> other.firstName) + (lastName <~> other.lastName)\n\n      //Comparison - last name, then first name; == < > and the rest are generated from it\n      operator <=> as pure\n        -> other as Person\n        <- rtn as Integer: lastName <=> other.lastName\n        if rtn == 0\n          rtn: firstName <=> other.firstName\n\n      //A hand-written <=> needs a hand-written #? hashing what it compares\n      operator #? as pure\n        <- rtn as Integer: #? `${lastName} ${firstName}`\n\n      override operator $ as pure\n        <- rtn as String: `${super.$()} ${firstName} ${lastName}`\n\n      override operator ? as pure\n        <- rtn as Boolean: super.?() and firstName? and lastName?\n\n    //Record using 'default operator' for auto-generated implementations\n    //Records can have ALL operators - don't write manual conversion functions!\n    Customer\n      name as String: String()\n      email as String: String()\n      age as Integer: Integer()\n\n      Customer()\n        ->\n          name as String\n          email as String\n          age as Integer\n        this.name :=? name\n        this.email :=? email\n        this.age :=? age\n\n      //Auto-generated JSON: {\"name\":\"...\",\"email\":\"...\",\"age\":...}\n      default operator $$\n\n      //Auto-generated String display\n      default operator $\n\n      //Auto-generated shallow copy, isSet, comparison and hashcode (== <> < > are generated from <=>)\n      default operator :=:\n      default operator ?\n      default operator <=>\n      default operator #?\n\n  defines program\n\n    Demo()\n      stdout <- Stdout()\n\n      steve <- \"Steve\"\n      limb <- \"Limb\"\n      p1 <- Person(PositiveId(1), steve, limb)\n      p2 <- Person(PositiveId(2), \"Stephen\", limb)\n\n      //Fuzzy match\n      similarity <- p1 <~> p2\n      stdout.println(`Similarity: ${similarity}`)\n\n      //Copy\n      p3 <- Person()\n      p3 :=: p1\n      stdout.println(`Copied: ${p3}`)\n\n      //Merge partial records\n      partial1 <- Person(PositiveId(1), steve, String())\n      partial2 <- Person(PositiveId(1), String(), limb)\n      partial1 :~: partial2\n      stdout.println(`Merged: ${partial1}`)\n\n      //Customer with default operators - NO manual JSON functions needed!\n      c1 <- Customer(steve, \"steve@example.com\", 30)\n\n      //$$record produces JSON automatically\n      json <- $$c1\n      stdout.println(`JSON: ${json}`)\n\n      //$record produces String automatically\n      stdout.println(`String: ${c1}`)\n\n      //Works on Lists too - $$ on List of Customer produces JSON array\n      customers <- [c1, Customer(\"Jane\", \"jane@example.com\", 25)]\n      stdout.println(`All: ${$$customers}`)\n\n//EOF"
    },

    "sanitization": {
      "pattern": "sanitized-input",
      "description": "Input sanitization for security - 'sanitized' modifier on String parameters",
      "keywords": ["sanitized", "String", "security", "InputSanitizer"],
      "code": "#!ek9\ndefines module example.security\n\n  defines function\n\n    //Sanitized parameter - automatically validated\n    //Block only executes if input passes security checks\n    processInput()\n      -> input as sanitized String\n      <- rtn as String: String()\n\n      if input?\n        //Safe to use - guaranteed clean\n        rtn: `Processed: ${input}`\n\n    //Manual sanitization using InputSanitizer\n    manualCheck()\n      -> userInput as String\n      <- rtn as String: String()\n\n      sanitizer <- InputSanitizer()\n      if clean <- sanitizer.sanitize(userInput)\n        rtn: `Manual clean: ${clean}`\n\n  defines program\n\n    Demo()\n      stdout <- Stdout()\n      stderr <- Stderr()\n\n      //Safe input\n      safeInput <- \"Hello World\"\n      result <- processInput(safeInput)\n      stdout.println(result)\n\n      //Potentially malicious input (SQL injection attempt)\n      badInput <- \"'; DROP TABLE users; --\"\n      result2 <- processInput(badInput)\n      if result2?\n        stdout.println(result2)\n      else\n        stderr.println(\"Input rejected as unsafe\")\n\n      //Manual sanitization with threat detection\n      sanitizer <- InputSanitizer()\n      threat <- sanitizer.detectThreat(badInput)\n      if threat?\n        stderr.println(`Threat detected: ${threat}`)\n\n//EOF"
    },

    "dispatcherPattern": {
      "pattern": "dispatcher-double-dispatch",
      "description": "Dispatcher pattern - EK9's replacement for instanceof/casting",
      "keywords": ["dispatcher", "method", "polymorphism", "override"],
      "code": "#!ek9\ndefines module example.dispatcher\n\n  defines class\n\n    //Base shape class\n    Shape as abstract\n      name() as pure abstract\n        <- rtn as String?\n\n    Circle extends Shape\n      radius <- Float()\n\n      Circle()\n        -> radius as Float\n        this.radius :=? radius\n\n      override name() as pure\n        <- rtn as String: \"Circle\"\n\n      radius() as pure\n        <- rtn as Float: radius\n\n      default operator ?\n\n    Square extends Shape\n      side <- Float()\n\n      Square()\n        -> side as Float\n        this.side :=? side\n\n      override name() as pure\n        <- rtn as String: \"Square\"\n\n      side() as pure\n        <- rtn as Float: side\n\n      default operator ?\n\n    //Renderer uses dispatcher for type-specific behavior\n    Renderer\n\n      //Dispatcher method - entry point\n      render() as dispatcher\n        -> shape as Shape\n        <- rtn as String: `Unknown shape: ${shape.name()}`\n\n      //Specific handler for Circle\n      render()\n        -> shape as Circle\n        <- rtn as String: `Circle with radius ${shape.radius()}`\n\n      //Specific handler for Square\n      render()\n        -> shape as Square\n        <- rtn as String: `Square with side ${shape.side()}`\n\n  defines program\n\n    Demo()\n      stdout <- Stdout()\n      renderer <- Renderer()\n\n      shapes <- [Circle(5.0), Square(3.0)]\n\n      //Compiler routes to correct overload automatically\n      //NO instanceof, NO casting needed!\n      for shape in shapes\n        stdout.println(renderer.render(shape))\n\n//EOF"
    },

    "restService": {
      "pattern": "rest-web-service",
      "description": "REST service with HTTP method mapping - GET, POST, DELETE, PATCH, PUT via operators",
      "keywords": ["service", "REST", "GET", "POST", "DELETE", "PATCH", "PUT", "PATH", "REQUEST", "CONTENT", "CONTEXT", "HTTPResponse", "HTTPContext"],
      "code": "#!ek9\ndefines module example.restservice\n\n  defines function\n\n    //Helper to create a non-cacheable HTTP response base\n    plainResponse()\n      <- rtn as HTTPResponse: () with trait of HTTPResponse\n        override cacheControl() as pure\n          <- rtn as String: \"no-store,max-age=0\"\n        override contentType() as pure\n          <- rtn as String: \"application/json\"\n        override contentLanguage() as pure\n          <- rtn as String: \"en\"\n        default operator ?\n\n  defines service\n\n    //Service mapped to /items URI path\n    Items :/items open\n\n      //GET with path parameter - maps to /items/{item-id}\n      byId() as GET for :/{item-id}\n        -> id as String :=: PATH \"item-id\"\n        <- response as HTTPResponse: (id: id, base: plainResponse()) with trait of HTTPResponse by base\n          override status() as pure\n            <- rtn as Integer: id? <- 200 : 404\n          override content()\n            <- rtn as Bytes: Bytes()\n          default operator ?\n\n      //POST - operator += maps to HTTP POST\n      operator += :/\n        -> request as HTTPRequest :=: REQUEST\n        <- response as HTTPResponse: (request: request, base: plainResponse()) with trait of HTTPResponse by base\n          status as Integer: 201\n          override content()\n            <- rtn as Bytes: request.content()\n          override status() as pure\n            <- rtn as Integer: status\n          default operator ?\n\n      //DELETE - operator -= maps to HTTP DELETE\n      operator -= :/{id}\n        -> id as String\n        <- response as HTTPResponse: (base: plainResponse()) with trait of HTTPResponse by base\n          override status() as pure\n            <- rtn as Integer: 204\n          default operator ?\n\n      //PATCH - operator :~: maps to HTTP PATCH (merge)\n      operator :~: :/{id}\n        ->\n          id as String\n          content as String :=: CONTENT\n        <- response as HTTPResponse: (base: plainResponse()) with trait of HTTPResponse by base\n          override status() as pure\n            <- rtn as Integer: 204\n          default operator ?\n\n      //PUT - operator :^: maps to HTTP PUT (replace)\n      operator :^: :/{id}\n        ->\n          id as String\n          content as String :=: CONTENT\n        <- response as HTTPResponse: (base: plainResponse()) with trait of HTTPResponse by base\n          override status() as pure\n            <- rtn as Integer: 200\n          default operator ?\n\n      //GET all items at root URI\n      listAll() :/\n        <- response as HTTPResponse: (base: plainResponse()) with trait of HTTPResponse by base\n          override content()\n            <- rtn as Bytes: Bytes(\"[]\", \"utf-8\")\n          default operator ?\n\n//EOF"
    },

    "textProperties": {
      "pattern": "text-i18n-localization",
      "description": "Text constructs for internationalization - locale-specific templates with string interpolation",
      "keywords": ["text", "locale", "i18n", "interpolation", "backtick", "template"],
      "code": "#!ek9\ndefines module example.text\n\n  defines record\n\n    Person\n      firstName as String: String()\n      lastName as String: String()\n\n      Person()\n        ->\n          firstName as String\n          lastName as String\n        this.firstName :=? firstName\n        this.lastName :=? lastName\n\n      operator $ as pure\n        <- rtn as String: `${firstName} ${lastName}`\n\n      default operator ?\n\n  defines text for \"en\"\n\n    WelcomePage\n\n      //Backticks for interpolated template strings\n      greeting()\n        -> person as Person\n        `Welcome ${person.firstName} ${person.lastName}`\n\n      //Quotes for literal (non-interpolated) text\n      mainMessage()\n        \"Welcome to our application.\"\n\n      //Escaped $ with \\$ for literal dollar sign\n      priceInfo()\n        -> amount as String\n        `Total: \\$${amount}`\n\n    Validator\n\n      tooShort()\n        -> input as String\n        `The value '${input}' is too short`\n\n  defines text for \"de\"\n\n    WelcomePage\n\n      greeting()\n        -> person as Person\n        `Willkommen ${person.firstName} ${person.lastName}`\n\n      mainMessage()\n        \"Willkommen in unserer Anwendung.\"\n\n      priceInfo()\n        -> amount as String\n        `Gesamt: \\$${amount}`\n\n    Validator\n\n      tooShort()\n        -> input as String\n        `Der Wert '${input}' ist zu kurz`\n\n  defines program\n\n    Demo()\n      stdout <- Stdout()\n      person <- Person(\"Steve\", \"Limb\")\n\n      //Runtime locale selection via constructor argument\n      english <- WelcomePage(\"en\")\n      stdout.println(english.greeting(person))\n      stdout.println(english.mainMessage())\n      stdout.println(english.priceInfo(\"42.00\"))\n\n      //Switch to German locale\n      deutsch <- WelcomePage(\"de\")\n      stdout.println(deutsch.greeting(person))\n\n      //Validation messages follow same locale pattern\n      validator <- Validator(\"en\")\n      stdout.println(validator.tooShort(\"Hi\"))\n\n//EOF"
    },

    "componentApplication": {
      "pattern": "component-application-di",
      "description": "Components, applications, and dependency injection - register bindings and inject with '!'",
      "keywords": ["component", "application", "register", "injection", "DI"],
      "code": "#!ek9\ndefines module example.components\n\n  defines trait\n\n    Logger\n      log() abstract\n        -> message as String\n\n    DataStore\n      save() abstract\n        -> content as String\n        <- rtn as Boolean?\n\n      load() abstract\n        -> id as String\n        <- rtn as String?\n\n  defines component\n\n    //Abstract component - defines injection interface\n    AppLogger as abstract\n      logger() as pure abstract\n        <- rtn as Logger?\n\n    //Concrete component - provides implementation\n    ConsoleLogger is AppLogger\n      override logger() as pure\n        <- rtn as Logger: () with trait of Logger\n          override log()\n            -> message as String\n            Stdout().println(message)\n          default operator ?\n\n    //Abstract data store component\n    AppDataStore as abstract\n      store() as pure abstract\n        <- rtn as DataStore?\n\n    //In-memory implementation\n    MemoryDataStore is AppDataStore\n      override store() as pure\n        <- rtn as DataStore: () with trait of DataStore\n          override save()\n            -> content as String\n            <- rtn as Boolean: content?\n          override load()\n            -> id as String\n            <- rtn as String: `Data for ${id}`\n          default operator ?\n\n  defines application\n\n    //Application wires components together\n    //register creates singleton bindings: implementation as abstract type\n    MyApp\n      register ConsoleLogger() as AppLogger\n      register MemoryDataStore() as AppDataStore\n\n  defines program\n\n    //Program with DI - 'with application of' enables injection\n    Demo() with application of MyApp\n      //The '!' suffix marks fields for dependency injection\n      appLogger as AppLogger!\n      dataStore as AppDataStore!\n\n      logger <- appLogger.logger()\n      store <- dataStore.store()\n\n      logger.log(\"Starting application\")\n\n      if store.save(\"test payload\")\n        logger.log(\"Data saved successfully\")\n\n      result <- store.load(\"item-1\")\n      if result?\n        logger.log(`Loaded: ${result}`)\n\n//EOF"
    },

    "transactionManagement": {
      "pattern": "transaction-management",
      "description": "Transaction trait for ACID-compliant operations; usable as a try-with-resources resource, but close does not roll back - roll back explicitly",
      "keywords": ["transaction", "commit", "rollback", "Closeable", "ACID", "try-with-resources", "Transaction"],
      "code": "#!ek9\ndefines module example.transaction\n\n  defines class\n\n    //Implement the Transaction trait - its commit() and rollback() do nothing by default\n    //Transaction extends Closeable, so it can be the resource of a try block\n    DatabaseTransaction with trait of Transaction\n      committed <- false\n\n      override commit()\n        committed: true\n\n      override rollback()\n        committed: false\n\n      override isCommitted() as pure\n        <- rtn as Boolean: Boolean(committed)\n\n      default operator ?\n\n  defines function\n\n    failingUpdate()\n      -> txn as DatabaseTransaction\n      if not txn.isCommitted()\n        throw Exception(\"update refused\")\n\n  defines program\n\n    Demo()\n      stdout <- Stdout()\n\n      //close is called at the end of the try, but it does NOT roll back:\n      //operator close is pure, so it cannot call rollback() - roll back explicitly\n      try\n        -> txn <- DatabaseTransaction()\n        stdout.println(\"Processing...\")\n        txn.commit()\n        stdout.println(`Committed: ${txn.isCommitted()}`)\n      catch\n        -> ex as Exception\n        stdout.println(`Failed: ${ex}`)\n\n      //A closeable held in a named local is a try resource; the inner try rolls it back on failure\n      try\n        -> second <- DatabaseTransaction()\n        try\n          failingUpdate(second)\n          second.commit()\n        catch\n          -> ex as Exception\n          second.rollback()\n          stdout.println(`Rolled back after: ${ex.reason()}, committed: ${second.isCommitted()}`)\n\n//EOF"
    },

    "networkingTypes": {
      "pattern": "networking-types-and-security",
      "description": "Network types: IPAddress, CIDR, Hostname, Networking utility, HTTPContext trait, Cookie record, SecurityGate and CORSPolicy abstract functions",
      "keywords": ["IPAddress", "CIDR", "Hostname", "Networking", "HTTPContext", "Cookie", "SecurityGate", "CORSPolicy", "network", "IP", "HTTP", "security"],
      "types": {
        "IPAddress": "IPv4/IPv6 address. Predicates: isV4, isV6, isLoopback, isPrivate, isMulticast, isLinkLocal, isAnyLocal, version. Literal parsing only (no DNS). Zone IDs rejected.",
        "CIDR": "Network range (address/prefix). Methods: networkAddress, prefixLength, contains (operator) for IPAddress, includesNetwork for CIDR, isV4, isV6. Host bits silently normalized.",
        "Hostname": "RFC 1123 hostname. Methods: labels (returns List of String), resolve (returns IPAddress). IDN support, auto-lowercase, trailing dot stripped.",
        "Networking": "Stateless gateway. Constants: loopbackV4/V6, anyV4/V6, privateA/B/C, loopbackV4Net. Env gateway: ipFromEnv, cidrFromEnv, hostnameFromEnv. Composition: cidrOf, resolve.",
        "HTTPContext": "HTTP request context trait. Methods: principal, isAuthenticated, isSecure, remoteAddress, requestId, header(name), contentType, withPrincipal(identity), cookie(name). Always set.",
        "Cookie": "HTTP cookie record with secure defaults. Fields: name, cookieValue, maxAge, path, domain, secure (true), httpOnly (true), sameSite (true=Strict). RFC 6265 encoding via $ operator.",
        "SecurityGate": "Abstract function: (HTTPContext) -> HTTPContext?. Returns enriched context on success, unset on rejection (401). Default rejects all. Use: MyGate is SecurityGate.",
        "CORSPolicy": "Abstract function: (String) -> Boolean?. Returns true = origin allowed, false = rejected, unset = no decision (rejects). Default rejects all."
      }
    }
  },

  "keywordIndex": {
    "description": "Quick lookup of keywords to relevant inline examples",
    "program": ["helloWorld", "simpleFunction"],
    "module": ["helloWorld", "constants"],
    "function": ["simpleFunction", "abstractFunction"],
    "class": ["simpleClass", "classExtension", "dynamicFunctions", "dynamicClasses"],
    "record": ["records"],
    "trait": ["traitComposition", "dynamicClasses"],
    "type": ["enumeration", "constants"],
    "enum": ["enumeration"],
    "extends": ["classExtension", "records"],
    "override": ["classExtension", "traitComposition"],
    "abstract": ["abstractFunction", "classExtension"],
    "pure": ["simpleFunction", "abstractFunction"],
    "if": ["ifStatement"],
    "switch": ["switchStatement", "enumeration"],
    "given": ["switchStatement"],
    "for": ["forLoop", "enumeration"],
    "while": ["whileLoop"],
    "try": ["tryCatch"],
    "catch": ["tryCatch"],
    "finally": ["tryCatch"],
    "cat": ["streams"],
    "filter": ["streams"],
    "map": ["streams"],
    "head": ["streams"],
    "tail": ["streams"],
    "collect": ["streams"],
    "pipe": ["streams"],
    "stream": ["streams"],
    "of": ["generics"],
    "List": ["generics", "streams"],
    "Dict": ["generics"],
    "Optional": ["generics"],
    "generic": ["generics"],
    "dynamic": ["dynamicFunctions", "dynamicClasses"],
    "capture": ["dynamicFunctions", "dynamicClasses"],
    "closure": ["dynamicFunctions", "dynamicClasses"],
    "tuple": ["dynamicClasses"],
    "by": ["dynamicClasses"],
    "with trait of": ["dynamicClasses"],
    "ternary": ["ternaryOperators"],
    "coalesce": ["ternaryOperators"],
    "??": ["ternaryOperators"],
    "?:": ["ternaryOperators"],
    "dispatcher": ["dispatcherPattern", "tryCatch"],
    "sanitized": ["sanitization"],
    "constant": ["constants"],
    "operator": ["simpleClass", "records", "enumeration"],
    "guard": ["ifStatement", "switchStatement", "whileLoop"],
    "service": ["restService"],
    "REST": ["restService"],
    "GET": ["restService"],
    "POST": ["restService"],
    "DELETE": ["restService"],
    "PATCH": ["restService"],
    "PUT": ["restService"],
    "PATH": ["restService"],
    "REQUEST": ["restService"],
    "CONTENT": ["restService"],
    "HTTPResponse": ["restService"],
    "HTTPRequest": ["restService"],
    "HTTPContext": ["restService", "networkingTypes"],
    "CONTEXT": ["restService"],
    "IPAddress": ["networkingTypes"],
    "CIDR": ["networkingTypes"],
    "Hostname": ["networkingTypes"],
    "Networking": ["networkingTypes"],
    "Cookie": ["networkingTypes"],
    "SecurityGate": ["networkingTypes"],
    "CORSPolicy": ["networkingTypes"],
    "network": ["networkingTypes"],
    "text": ["textProperties"],
    "i18n": ["textProperties"],
    "locale": ["textProperties"],
    "interpolation": ["textProperties"],
    "template": ["textProperties"],
    "component": ["componentApplication"],
    "application": ["componentApplication"],
    "register": ["componentApplication"],
    "injection": ["componentApplication"],
    "DI": ["componentApplication"],
    "transaction": ["transactionManagement", "componentApplication"],
    "Transaction": ["transactionManagement"],
    "commit": ["transactionManagement"],
    "rollback": ["transactionManagement"],
    "ACID": ["transactionManagement"],
    "$": ["simpleClass", "records"],
    "$$": ["records"],
    "default": ["simpleClass", "records", "enumeration"],
    "JSON": ["records", "restService"],
    "default operator": ["simpleClass", "records"]
  },

  "mcpOracleTools": {
    "description": "MCP tools available via ek9 -mcp or ek9 -ide for AI agents to query the compiler. All tools return structured JSON.",
    "discovery": [
      {
        "name": "ek9_find_construct",
        "description": "Find type constructs (classes, traits, records, functions, components) by unqualified name across all compiled modules",
        "parameters": {"name": "string (required) — the unqualified type name to search for"},
        "returns": "Array of matches with fullyQualifiedName, moduleName, genus, sourceFile, line",
        "usage": "Use when you know a type name but not its module or file location"
      }
    ],
    "locationBased": [
      {
        "name": "ek9_query_symbol",
        "description": "Query symbol information at a specific source location",
        "parameters": {"file": "string", "line": "integer"},
        "returns": "Symbol name, type, genus, category, squirrelled metadata"
      },
      {
        "name": "ek9_query_construct",
        "description": "Query complete structure of class/record/trait/component at a location",
        "parameters": {"file": "string", "line": "integer"},
        "returns": "Fields, methods, operators, constructors, inheritance, metrics"
      },
      {
        "name": "ek9_query_type_hierarchy",
        "description": "Query type hierarchy including super chain, traits, discovered subtypes, and source locations",
        "parameters": {"file": "string", "line": "integer"},
        "returns": "Super chain, all traits, sealed status, discovered subtypes with source locations, type parameters"
      },
      {
        "name": "ek9_query_scope",
        "description": "Query scope chain and active guards at a location",
        "parameters": {"file": "string", "line": "integer"},
        "returns": "Scope chain, active guards, purity constraints, variable visibility"
      },
      {
        "name": "ek9_query_dispatchers",
        "description": "Query dispatcher handler methods for a dispatcher class",
        "parameters": {"file": "string", "line": "integer"},
        "returns": "Dispatcher status, dispatch methods, handler list, sealed type info"
      },
      {
        "name": "ek9_query_flow",
        "description": "Query function/method complexity and flow analysis metrics",
        "parameters": {"file": "string", "line": "integer"},
        "returns": "Cyclomatic complexity, statement count, nesting depth, purity, expression complexity"
      },
      {
        "name": "ek9_query_call_graph",
        "description": "Query call graph showing callers and callees of a function/method",
        "parameters": {"file": "string", "line": "integer"},
        "returns": "Callers, callees, parameters, return type, purity"
      },
      {
        "name": "ek9_query_effective_api",
        "description": "Query effective API of a type including inherited methods",
        "parameters": {"file": "string", "line": "integer"},
        "returns": "All callable methods (own + inherited), operators, total count"
      },
      {
        "name": "ek9_query_module",
        "description": "Query module-level constructs listing",
        "parameters": {"file": "string", "line": "integer"},
        "returns": "Module name, all constructs with name/genus/line, references"
      },
      {
        "name": "ek9_query_pipeline",
        "description": "Query stream pipeline analysis",
        "parameters": {"file": "string", "line": "integer"},
        "returns": "Pipeline stages, source type, terminal operation, element types"
      },
      {
        "name": "ek9_query_references",
        "description": "Find all references to a symbol across all compiled modules",
        "parameters": {"file": "string", "line": "integer"},
        "returns": "Declaration location, type references, extends, trait implementations, field types"
      }
    ],
    "programLevel": [
      {
        "name": "ek9_query_diagnostics",
        "description": "Query compilation diagnostics (errors, warnings)",
        "parameters": {},
        "returns": "Diagnostic list with file, line, severity, message, error code"
      },
      {
        "name": "ek9_query_workspace",
        "description": "Query workspace structure and source file listing",
        "parameters": {},
        "returns": "Source files, module names, compilation state"
      },
      {
        "name": "ek9_query_compilation_state",
        "description": "Query current compilation state and phase",
        "parameters": {},
        "returns": "Current phase, compilation status, error count"
      },
      {
        "name": "ek9_query_di_wiring",
        "description": "Query DI wiring: applications, registrations, injection sites, programs, health",
        "parameters": {"application": "string (optional) — filter to specific application"},
        "returns": "Applications with registrations, injection sites, satisfaction status, health verdict"
      },
      {
        "name": "ek9_query_module_dependencies",
        "description": "Query module dependency graph with cross-module references and cycle detection",
        "parameters": {"includeBuiltins": "boolean (optional, default false)"},
        "returns": "Modules, dependency edges with kinds and counts, graph metrics"
      }
    ],
    "utility": [
      {
        "name": "ek9_compile",
        "description": "Compile the workspace (required before query tools)",
        "parameters": {},
        "returns": "Compilation result with phase reached and error count"
      },
      {
        "name": "ek9_version",
        "description": "Get EK9 compiler version",
        "parameters": {},
        "returns": "Version string"
      },
      {
        "name": "ek9_help",
        "description": "Get help on EK9 topics, types, or error codes",
        "parameters": {"topic": "string"},
        "returns": "Help text for the topic"
      },
      {
        "name": "ek9_explain_error",
        "description": "Get detailed explanation for an error code",
        "parameters": {"code": "string"},
        "returns": "Error diagnosis, fix actions, examples"
      },
      {
        "name": "ek9_paradigm",
        "description": "Get EK9 language paradigm summary",
        "parameters": {},
        "returns": "Design decisions, excluded features, philosophy"
      },
      {
        "name": "ek9_ask",
        "description": "Search Q&A knowledge base",
        "parameters": {"query": "string"},
        "returns": "Matching Q&A entries with code examples"
      },
      {
        "name": "ek9_format",
        "description": "Format EK9 source file",
        "parameters": {"file": "string"},
        "returns": "Formatted source"
      }
    ]
  },

  "oracleEditingTools": {
    "description": "Oracle editing tools that modify EK9 source code. AI agents call these instead of generating EK9 syntax directly. Each tool returns a Changeset with preview, conflicts, and source edits. The concept-to-tool pipeline: (1) ask Q&A about concept, (2) receive syntax + oracleToolHint, (3) call editing tool to produce correct code.",
    "principle": "The AI handles intent (what to create/modify); the Oracle handles correctness (EK9 syntax, indentation, insertion position, operator signatures). The model never generates EK9 tokens from its own weights for structural operations.",
    "implemented": [
      {
        "name": "ek9_add_field",
        "description": "Add a typed field to a class, record, or component with genus-specific rules",
        "parameters": {
          "constructName": "string — unqualified type name",
          "fieldName": "string — new field name",
          "typeName": "string — field type (e.g., String, Integer)",
          "defaultValue": "string (optional) — initial value (required for records)",
          "rawDeclaration": "string (alternative) — full EK9 field declaration (e.g., 'name as String!')"
        },
        "genusRules": "Records: public, must have default. Classes: private, default optional. Components: use '!' suffix for injection.",
        "validation": "Grammar-validated via ANTLR parser (FieldDeclarationValidator). Rejects duplicates."
      },
      {
        "name": "ek9_add_method",
        "description": "Add a method to a class, trait, component, or service with correct signature and body",
        "parameters": {
          "constructName": "string — unqualified type name",
          "name": "string — method name",
          "parameters": "array of {name, type} — method parameters",
          "returnType": "string (optional) — return type",
          "pure": "boolean — mark as pure",
          "isAbstract": "boolean — abstract (traits/abstract classes only)",
          "override": "boolean — override inherited method"
        },
        "generates": "Method declaration with parameters, return value declaration, require statements for params, and '//AI: Implement' comment in body for local LLM to fill.",
        "validation": "Checks genus supports methods. Rejects duplicate signatures (name + parameter types)."
      },
      {
        "name": "ek9_add_operator",
        "description": "Add operators to classes/records in three modes: all defaults, single default, or full skeleton",
        "parameters": {
          "constructName": "string — unqualified type name",
          "mode": "'all_defaults' | 'default' | 'skeleton'",
          "operatorSymbol": "string (for default/skeleton) — operator symbol (e.g., '==', '$', '?', '<=>')"
        },
        "modes": {
          "all_defaults": "Inserts 'default operator' — compiler generates all standard operators",
          "default": "Inserts 'default operator X' — compiler generates single operator",
          "skeleton": "Generates full field-based implementation with correct operator signature"
        },
        "skeletonOperators": "?, $, ==, <>, <=>, #?, :=: — each with field-by-field logic. Auto-detects override from super chain."
      },
      {
        "name": "ek9_add_constructor",
        "description": "Add constructor to class/record with 5 modes and purity enforcement",
        "parameters": {
          "constructName": "string — unqualified type name",
          "mode": "'private_no_arg' | 'default_all' | 'skeleton_all' | 'from_fields' | 'make_all_pure'",
          "fieldNames": "array of string (for from_fields mode) — subset of fields",
          "pure": "boolean (for skeleton_all mode)"
        },
        "modes": {
          "private_no_arg": "Blocks default construction: 'default private ConstructorName()'",
          "default_all": "Compiler-generated from all fields (no body)",
          "skeleton_all": "Explicit body with ':=:' copy per field",
          "from_fields": "Constructor from field subset, auto-determines purity",
          "make_all_pure": "Retrofits 'as pure' on all existing constructors"
        },
        "purityRule": "If any existing constructor is pure, all new ones must be pure."
      },
      {
        "name": "ek9_expand_default_operator",
        "description": "Expand 'default operator' or 'default operator X' into full skeleton body",
        "parameters": {
          "constructName": "string — unqualified type name",
          "operatorSymbol": "string — specific operator, or 'all' for batch expansion",
          "cursorLine": "integer — line containing the default operator declaration"
        },
        "generates": "Full field-based operator implementation replacing the default declaration."
      },
      {
        "name": "ek9_collapse_to_default_operator",
        "description": "Replace explicit operator implementation with 'default operator X' (inverse of expand)",
        "parameters": {
          "constructName": "string — unqualified type name",
          "operatorSymbol": "string — operator to collapse",
          "cursorLine": "integer — line containing the operator declaration"
        },
        "defaultableOperators": ["<=>", "==", "<>", "<", "<=", ">", ">=", "?", "$", "$$", "#?", ":=:"]
      },
      {
        "name": "ek9_organize_references",
        "description": "Remove unused type references from the references block (like 'optimize imports')",
        "parameters": {
          "file": "string — source file path"
        },
        "generates": "Deletes unused reference lines. Removes entire references block if all unused."
      },
      {
        "name": "ek9_toggle_block_comment",
        "description": "Toggle EK9 block comments ('<!-' / '-!>') around a line range",
        "parameters": {
          "startLine": "integer — first line (1-based)",
          "endLine": "integer — last line (1-based)"
        },
        "generates": "Adds markers if uncommented, removes if commented. Rejects nesting."
      },
      {
        "name": "ek9_surround_with",
        "description": "Wrap selected lines in a control flow construct with correct indentation and //AI: placeholder comments",
        "parameters": {
          "sourceText": "string — full source text",
          "fileName": "string — source file name",
          "startLine": "integer — first line of selection (1-based)",
          "endLine": "integer — last line of selection (1-based)",
          "type": "'IF' | 'IF_ELSE' | 'TRY_CATCH' | 'TRY_CATCH_FINALLY' | 'FOR_RANGE' | 'WHILE'"
        },
        "generates": "Re-indents selected lines +2 spaces inside the control flow wrapper. Adds '//AI:' comments at each placeholder (condition, else branch, catch handler, finally cleanup, range bounds).",
        "note": "Critical in EK9 where indentation defines scope — manual re-indentation is error-prone."
      }
    ],
    "designedNowShipped": {
      "note": "Where the tools this section once listed as designed went: all but one shipped, mostly under different names. The full live list (180 tools) is ek9_query_tool_catalogue, or 'ek9 -tool' on the command line.",
      "ek9_scaffold": "ek9_new_construct (programs: ek9_add_program; applications: ek9_add_application)",
      "ek9_implement": "ek9_implement_methods (adopting a trait the class does not yet declare: ek9_adopt_trait)",
      "ek9_add_member": "ek9_add_method / ek9_add_field / ek9_add_constructor / ek9_add_operator",
      "ek9_rename_symbol": "ek9_rename_symbol",
      "ek9_generate_dispatcher": "ek9_generate_dispatcher",
      "ek9_generate_delegation": "ek9_generate_delegation",
      "ek9_convert_to_stream": "ek9_advise_loop (advises; never rewrites a loop automatically)",
      "ek9_convert_to_guard": "ek9_apply_guard_pattern",
      "ek9_insert_guard": "ek9_apply_guard_pattern",
      "ek9_make_pure": "ek9_change_signature / ek9_fix_purity_contract",
      "ek9_insert_coalescing": "ek9_insert_coalescing",
      "ek9_insert_pipeline": "not built: ek9_advise_loop says when a loop reads better as a stream pipeline",
      "ek9_insert_dynamic_function": "ek9_create_dynamic_function",
      "ek9_insert_dynamic_class": "ek9_create_dynamic_class"
    }
  },

  "qaSystem": {
    "description": "Built-in Q&A knowledge base for developers and AI assistants",
    "listQuestions": "ek9 -q",
    "askQuestion": "ek9 -q <words> (EK9-focused: answer + code example)",
    "askQuestionById": "ek9 -q <number> (direct Q&A fetch by ID)",
    "askMigration": "ek9 -qm <words> (migration-focused: answer + language comparisons)",
    "trainingDump": "ek9 -Q (instruction JSONL to stdout)",
    "trainingDumpChat": "ek9 -Qc (mlx_lm chat JSONL to stdout, resolved cross-refs)",
    "trainingDumpChatThinking": "ek9 -Qct (mlx_lm chat JSONL with Qwen3 thinking traces)",
    "trainingDumpSplit": "ek9 -Qt (write ek9_training_data/train.jsonl + valid.jsonl, 90/10 stratified)",
    "trainingDumpSplitThinking": "ek9 -Qtt (training split with Qwen3 thinking traces)",
    "totalQuestionsImplemented": 565,
    "categoriesImplemented": 49,
    "totalQuestionsPlanned": 2034,
    "categoriesPlanned": 197,
    "format": "JSONL instruction/response (-Q) or mlx_lm chat with system prompt (-Qc/-Qt/-Qct/-Qtt)",
    "languagesCovered": ["Python", "Java", "Rust", "Go", "C++", "Kotlin", "TypeScript", "C#"]
  }
}
