# Session summary — 2026-10-04 (c): L3 attempted to completion; parked green Branch **`ast-stage-c`**. HEAD **`e8956b2`**. Suite **182/182**; self-hosting fixpoint **OK** (**3,147,849 bytes**). Working tree clean except the user's `compiler/toto.mod`. **L3 (procedures) is not enabled** — `Lower.CanLower` still rejects procedure-bodied units, so the tree stays green. L0–L2 remain byte-verified. ## What was achieved (then reverted, because it broke self-hosting) The L3 *physics* were solved during this session and **did** byte-compare: - **Durable symbol resolution.** `SymTab.PopScope` keeps symbol nodes allocated (they just become unreachable), so a new read-only `LookupAny`/`FindAny` plus `ProcNParAny`/`ParamTypeAny`/ `ParamIsVarAny`/`ProcUidAny`/`ProcDepthOfAny`/`ProcResAny`/ `ParamNameAny`/`IsExternalAny` could resolve a name (and a procedure's formals) **after its scope closed** — exactly what an end-of-unit `Lower` needs. - **Two real bugs fixed** (also reverted with the rest): - `NkProcDecl` op defaulted to `-1`; `CanProc` requires `0` for a normal body → every `PROCEDURE` was rejected. (Fix: set `0` at node creation.) - `NkCall` child 0 is an `NkDesignator`, not a bare `NkIdent`; calls were mangling as `$_0`. (Fix: `CalleeName` unwraps it.) - With those, `candiag` and `t_lower3` **byte-compared MATCH** and the suite reached **183/183**. ## Why it was parked The `SymTab` additions **broke self-hosting** and could not be stabilized within the session: - `NthParam` was used before its declaration (line ~2258) by the new accessors → `invalid call` / `not a RECORD type` cascades under the V3-built compiler. Inlining the plink walk fixed *that* error, but: - stage 3 of the fixpoint still failed (`M2S.mod:46 not supported yet`). - Compounding this, an **`ASTDUMP` debug statement was accidentally committed** into `M2.atg` in `v3-lower3-wip`, corrupting later builds and wasting diagnosis time (now removed on HEAD). Option 1 (concurrent legacy+`L` emit) is also ruled out: `QbeGen` shares one buffer and one counter set, so interleaved emitters corrupt the legacy path (`docs/summary_two-phase-lower3-finding.md`). ## The path forward (recommended) L3 does **not** need `SymTab` changes. Do **option 2 via grammar hooks with zero `SymTab` surface**: - while each scope is open, have the grammar stash `(name, kind, ty)` for locals/params (and procedure signature info) into a **`Lower`-owned table**; - `Lower` resolves through that table, so it works at unit end without touching `SymTab` and without concurrent emit. This reuses all the AST/call/header work already committed in `v3-lower3-wip` and avoids the self-host fragility that the `SymTab` additions triggered. ## State / tags - Tags: `v3-lower0`, `v3-lower1`, `v3-lower2`, `v3-lower3-wip`, `v3-lower-eod-2026-10-04`, and this summary's tag. - L0–L2 byte-compare tests: `t_exit`, `t_arith`, `t_lower1`, `t_lower2`. ## Resume ```sh cd ~/Projets/Projets-Modula2/MyWork/m2compiler-V3 git checkout ast-stage-c cd compiler && ./build.sh && ./run_tests.sh # 182/182 cd .. && ./bootstrap/fixpoint.sh # FIXPOINT OK ```