# F-05 — executionContext.js: ExecutionClassificationMap is a parallel structure to the AST

**Severity:** Design  
**File:** `core/src/analysis/executionContext.js`  
**Category:** Architectural redundancy — parallel classification to AST  
**Remediation appropriate:** Partial — Tier 3 (major change; evaluate carefully)

---

## Context

`buildExecutionClassificationMap()` in `executionContext.js` does a full document scan using
regex to produce a per-line array of `{ isOutput, isExecutable, isInvalidExecutable }` flags.
This map is consumed by virtually every validator. It was built before the AST existed.

---

## The redundancy

The AST parser already classifies every line precisely:

| ECM flag | AST equivalent |
|---|---|
| `isOutput` | `OutputLine` node |
| `isExecutable` (keyword-led) | `IfStatement`, `DoStatement`, `VarStatement`, `SetStatement`, `MacroDeclaration`, etc. |
| `isExecutable` (identifier-led) | `AssignStatement`, `ExpressionStatement` |
| `isInvalidExecutable` | `UnknownLine` node |
| comment-only | `CommentLine` node |

The current `buildExecutionClassificationMap` achieves the same classification through:
1. Hash-mode state tracking (HASH-ON/HASH-OFF lines)
2. `isLikelyExecutableLine()` — a regex with 40+ keyword alternatives
3. `isInvalidExecutable` detection for HASH-OFF non-prefixed lines

The AST parser already handles all of these cases correctly through the lexer's hash-mode
tracking and the parser's keyword dispatch.

---

## Why this matters

1. **Two sources of truth for line classification.** The AST says a line is a `SetStatement`.
   The ECM says it is `isExecutable`. If the lexer/parser changes its handling of some construct
   (e.g., a new keyword is added), the ECM regex must also be updated. This is the same
   multi-location divergence risk as the v1 finding about `ACURITY_KEYWORDS`.

2. **`isLikelyExecutableLine()` is incomplete.** It has its own keyword list that differs from
   the lexer's `KEYWORDS` set. Specifically, the ECM recognises `ELSEIF` as an executable keyword
   (it's in the regex), but `ELSEIF` is not a valid Architect keyword (removed from the codebase
   per recent work). The lexer's `KEYWORDS` set is the single source of truth for what is valid.

3. **HASH-OFF support is simpler in the AST.** The ECM has complex multi-line state tracking
   for HASH-OFF mode. The lexer handles this statelessly per token — tokens in HASH-OFF output
   lines are `OUTPUT_TEXT` tokens, and the parser wraps them in `OutputLine` nodes. No secondary
   state machine is needed.

---

## The complication

The ECM is structurally simpler for validators to consume — `O(1)` lookup by line index vs.
AST tree traversal. This is a real performance concern. The AST walk to classify lines would
need to produce a similar array, not replace the array with a tree walk in each validator.

The key insight is that the ECM could be **built from the AST** rather than from regex, while
**keeping the same consuming interface**:

```javascript
function buildExecutionClassificationMapFromAst(ast, lineCount) {
    const map = new Array(lineCount).fill(null).map(() => ({
        isOutput: false, isExecutable: false, isInvalidExecutable: false
    }));

    function classifyStatements(stmts) {
        for (const stmt of stmts) {
            if (stmt.line !== undefined) {
                const cls = map[stmt.line];
                if (!cls) continue;
                if (stmt.type === NodeType.OutputLine) {
                    cls.isOutput = true;
                } else if (stmt.type === NodeType.UnknownLine) {
                    cls.isInvalidExecutable = true;
                    cls.isExecutable = false;
                } else if (stmt.type !== NodeType.CommentLine) {
                    cls.isExecutable = true;
                }
            }
            // recurse into block bodies
            if (stmt.body) classifyStatements(stmt.body);
            if (stmt.consequent) classifyStatements(stmt.consequent);
            // ... etc.
        }
    }
    classifyStatements(ast.statements);
    return map;
}
```

This preserves the `ecm[lineIndex].isOutput` interface but eliminates the regex.

---

## Assessment

**The change is correct and worth doing** — but it is Tier 3 because:
1. The ECM is consumed by ~12 validators and by `documentFacts.js` itself.
2. The current ECM has test coverage through syntax tests; a new implementation needs
   equivalent coverage.
3. The HASH-OFF output-line detection in the ECM currently uses `buildOutputLineMap()` which
   does its own full scan — this also needs to be replaced with AST-based output detection.

**Intermediate step:** Document `isLikelyExecutableLine()` as a known incomplete approximation
and add a comment that it should be replaced with AST-based classification. Add a `// FIXME:`
noting the `ELSEIF` dead entry in the regex.

**Recommended path:** After F-01, F-02, F-03 are applied (removing regex scans from validators),
the ECM becomes the last remaining non-AST classification source. It can then be migrated with
a well-defined before/after contract, backed by the existing syntax test suite.
