diff --git a/current/CHECKPOINT-MEM.md b/current/CHECKPOINT-MEM.md
index 9d5c19e..b83e4e2 100644
--- a/current/CHECKPOINT-MEM.md
+++ b/current/CHECKPOINT-MEM.md
@@ -5,6 +5,39 @@ Tracking checkpoint for the mem.sx Zig-aligned implementation
## Last completed step
+**Allocator primitive rename — `alloc`→`alloc_bytes`,
+`dealloc`→`dealloc_bytes` (`88bae3c`, 2026-06-11).** Phase 4's naming
+piece pulled forward per Agra's call (Option A in the 2.2 naming fork):
+the bare names free up NOW so the Phase 2.2 helpers land under their
+FINAL Appendix-A names (`alloc(T,n)` / `free(s)` / `create` / `destroy`
+/ `clone` / `resize` / `mem_realloc`) with zero later churn. Phase 4
+shrinks to signature expansion (size/align params + resize/remap +
+deinit) only.
+
+What changed (signatures unchanged — 2-method era continues):
+- `std.sx` protocol decl; `std/mem.sx` 6 impls + internals; library
+ call sites (glyph_cache/json/state/renderer); 13 example .sx files
+ (incl. the two custom `Tracer` impls in 0306/0808 — caught broken
+ mid-step by stdout-diff review BEFORE pinning; the first `--update`
+ had captured their broken output, restored + fixed + re-pinned).
+- Compiler: `interp.zig` thunk-name lookups
+ (`__thunk_CAllocator_Allocator_alloc_bytes`/`_dealloc_bytes`) — the
+ ONE hard name coupling; `allocViaContext` + default-context emission
+ are slot-positional (rename-safe); ffi.zig's `"alloc"` check is the
+ Obj-C `Cls.alloc()` intercept (unrelated, untouched).
+- 37 `.ir` snapshots re-pinned (thunk symbols + reflection
+ field-name strings); all 37 verified stdout-clean before update;
+ path-noise churn reverted.
+- External repos migrated + gated: game (`main.sx`, SxChess.app
+ builds + bundles) and m3te (`board_fx.sx`, `main.sx`,
+ `tools/key_particle.sx`; tools/run_tests.sh 23/23). Obj-C zero-arg
+ `.alloc()` calls are NOT protocol calls — excluded by pattern.
+
+Gates: zig build 0, zig build test 0, suite 582/582, m3te 23/23,
+game rebuilt.
+
+Prior steps (2026-05-25 era)
+
- **`resolveType(null) → .s64` silent fallback removed.** `resolveType`
now takes a non-optional `*const Node`; the `null → .s64` branch is
gone. Callers that legitimately had no annotation handle it
@@ -140,8 +173,66 @@ Tracking checkpoint for the mem.sx Zig-aligned implementation
of zeros, on both interp and codegen paths. 156/156 example tests
+ chess clean.
+
+
## Current state
+**std.sx-as-pure-re-exports plan COMPLETE** (2026-06-11,
+Agra-directed end-to-end). std.sx is now a facade of alias
+declarations only (`49a36bb`): implementations live in std/core.sx
+(builtins, libc escape hatch, Context/Allocator/Into/Source_Location/
+`string` — the reserved name needs and permits no alias), std/fmt.sx
+(print/format/any_to_string/string ops), std/list.sx (List); the
+namespace tail is unchanged and `core`/`fmt`/`list` carry alongside
+it. Consumer surface byte-identical; 37 .ir snapshots re-pinned
+(pure renumbering, digit-normalized diff empty).
+
+Issues filed AND resolved along the way (all same-day,
+Agra-authorized): 0120 generic-struct head aliases (`f2db8ec`,
+example 0211), 0121 fn aliases of every kind incl. comptime-pack
+(`721369a`, example 0546), 0122 whole-program passes pinning the
+source context per decl (`340be40` — latent on master, exposed by
+the facade; coverage 0129/1047/1049/1052/1053/1056). Protocol
+aliases (plain + Into's xx path) and #builtin/#foreign aliases
+probe-verified working; param-protocol impl dot-calls are a designed
+opt-in gap, not a bug.
+
+Gates at completion: zig build test 426/426, suite 588/588,
+m3te 23/23, game SxChess builds + bundles. Suite baseline 588.
+
+**(2026-06-11) Phase-by-phase ground truth** (verified against the
+tree; the sections below this one are the 2026-05-25 era record):
+- Phase 1 DONE (xx heap-copy via context.allocator; serializer; the
+ whole implicit-Context refactor).
+- Phase 2.1 DONE-equivalent: allocators.sx became `std/mem.sx` via the
+ STDLIB restructure (`59f0aa7`).
+- **Primitive rename DONE (`88bae3c`)** — see "Last completed step".
+ Protocol is `alloc_bytes(size)` / `dealloc_bytes(ptr)` (2-method
+ era signatures).
+- Phase 2.2 helpers: NOT YET — next step. Final names per Appendix A:
+ `create(a,$T)->*T`, `alloc(a,$T,n)->[]T`, `destroy(a,ptr)`,
+ `free(a,slice)`, `clone(src,a)`, `resize(slice,a,n)`,
+ `mem_realloc(a,ptr,old,new,align)`. The `free` helper requires
+ REMOVING std.sx's bare `malloc`/`free` foreign decls (lines ~13-16;
+ `libc_malloc`/`libc_free` aliases already exist) and migrating ~30
+ bare uses (mostly examples) — fold into the helpers step.
+- Phase 2.3: TrackingAllocator exists; FailingAllocator +
+ LoggingAllocator missing.
+- Phase 3 (caller migration to helpers): not started.
+- Phase 4: now signature-expansion only (alloc_bytes gains alignment;
+ dealloc_bytes gains size+align; + resize/remap/deinit) — naming
+ piece already landed.
+- Phase 5 (--leak-check + specs Memory chapter): not started.
+- NOTE: plan's "init returns Allocator via xx heap-copy" section is
+ SUPERSEDED by the by-value convention (CLAUDE.md "Allocator
+ construction"); BufAlloc.init still returns *BufAlloc (state lives
+ in the caller's buffer — review at Phase 4 whether to align).
+- Suite baseline 582; gates now: zig build && zig build test &&
+ bash tests/run_examples.sh (+ m3te 23/23 + game build for
+ std-touching steps). The old 148-159 counts below are historical.
+
+2026-05-25 era state (historical)
+
Phase 0.0c shipped (allocator API on one-line `init` returning `*T`;
TrackingAllocator added). 148/148 tests pass.
@@ -270,8 +361,77 @@ bypass) is FULLY CLOSED. User-typed `context.allocator.X` flows
through the real protocol vtable at codegen *and* runs the same
chain at comptime in the interp. No remaining shortcut.
+
+
+## Current state
+
+**Opt-in UFCS landed (`a47ea14`, 2026-06-11)** — the canonical dot
+surface now works: `context.allocator.create(Session)`,
+`slice.clone(a)`. Agra specified the model in-session (three
+clarifying rulings): free-fn dot-calls are OPT-IN via
+`name :: ufcs (params) { body }` (NEW declaration form) or
+`name :: ufcs target;` (alias); plain fns are direct/`|>`-only with a
+tailored rejection. Implementation inverted TWO pre-existing gaps:
+unannotated fns used to dot-dispatch (removed; 6 example files
+audited + migrated, ZERO reliance in m3te/game) and aliases did NOT
+dot-dispatch at all (0036 only ever pinned direct+pipe). Generic ufcs
+fns bind `$T` from the receiver; protocol receivers dispatch own
+methods first, fall through to ufcs fns for non-members
+(protocolHasMethod gate in lower/call.zig). Root-cause bonus:
+`inferGenericReturnType` now delegates to `buildTypeBindings` (ONE
+binding builder) — structured generic params (`[]$T`) no longer type
+direct calls as `T{}` stubs. mem.sx helpers marked `ufcs`; specs.md
+§UFCS rewritten around the opt-in matrix. Tests: 0053 (matrix), 1166
+(rejection), 0838 re-pinned (dot+pipe+direct). Gates: 585/585, zbt 0,
+m3te 23/23, game builds. 0119 RESOLVED (final banner).
+
+**Phase 2.2 DONE (`84e0fb0`, 2026-06-11).** The 0119 block resolved as
+a LANGUAGE RULING, not a compiler fix (Agra, in-session): dot-form UFCS
+on generic free functions is not the contract — UFCS free-fn
+dot-dispatch is the annotated `ufcs` alias mechanism (concrete
+targets), and the FLUENT spelling for free functions is the pipe:
+`context.allocator |> create(Session)` desugars at parse time to the
+direct call, which dispatches generics through normal monomorphization
+(verified for protocol + slice receivers). specs.md §UFCS corrected
+(it overstated "generic functions" for the dot form). Issue 0119
+carries the RESOLVED banner; residual unfiled corner: a `ufcs` alias
+naming a generic target doesn't dot-dispatch either.
+
+Landed:
+- `std/mem.sx` typed helpers, era-complete bodies, final names:
+ `create(a,$T)->*T`, `destroy(a,*$T)`, `alloc(a,$T,n)->[]T`,
+ `free(a,[]$T)`, `clone(src,a)`, `resize(slice,a,n)` (fresh storage +
+ copy + free-old; old slice dangles), `mem_realloc(a,ptr,old,new,
+ align)` (alloc+copy+dealloc; align unhonored until the protocol
+ carries alignment — documented inline). NO zero-init (Zig-aligned).
+- std.sx bare `malloc`/`free` decls REMOVED (libc_malloc/libc_free
+ stay as the raw escape hatch); users migrated: examples
+ 0205/0604/0804/0806/0808/1610 + game/chess/pieces.sx.
+- Regression: examples/0838-memory-helpers.sx (whole surface, direct +
+ `|>` spellings, TrackingAllocator balances 8/8). 37 .ir re-pins
+ (constant-pool renumbering from the removed decls — the
+ ISSUE-MEM-004 cascade; all verified stdout-clean pre-update).
+- KNOWN GAP: `string` does NOT bind a `[]$T` param (probe: "unknown
+ type 'T'") — string-clone story deferred (sx string is [:0]u8-shaped;
+ decide at Phase 4/5).
+
+Gates: zig build 0, zbt 0, suite 583/583, m3te 23/23, game SxChess.app
+builds.
+
## Next step
+**Phase 2.3 — diagnostic wrappers**: `FailingAllocator` (delegates to
+parent while budget remains, then alloc returns null) and
+`LoggingAllocator` (tag-prefixed prints, delegates) in `std/mem.sx`,
+2-method-era bodies, by-value `init` per the CLAUDE.md convention.
+Then Phase 3 (migrate std.sx/library/example callers to the helpers —
+NOTE std.sx itself cannot import mem.sx (circular); its internals keep
+alloc_bytes), Phase 4 (protocol signature expansion: alignment + size
+on the primitives, resize/remap/deinit — naming already landed),
+Phase 5 (--leak-check + specs Memory chapter).
+
+2026-05-25 era next-step record (historical)
+
Phase 1.3 (closure env allocation through context) shipped in commit
`8e21cc5`. Phase 1.4 (codegen serializer for all interp Value
variants) shipped this session. Phase 1.2 (free / malloc through
@@ -300,6 +460,8 @@ Open follow-ups, in roughly the order they make sense:
the canonical buffer/string case is already handled by `[]T` /
`string`.
+
+
## Phase 0.3 audit findings — chess allocator usage (closed)
After Step 5 / matchContextAllocCall removal, every consumer call
@@ -324,6 +486,83 @@ Allocator value naturally.
## Log
+- **2026-06-11 (latest)** — Redundant flat `#import "modules/std/mem.sx"`
+ dropped from the facade (`c75cd9c`, Agra spotted it): the tail's
+ `mem ::` import already covers the graph needs (ufcs helpers +
+ CAllocator); the double import was duplicating lowered IR (~2.5k
+ lines across 37 re-pinned .ir snapshots, output byte-identical).
+ Gates: suite 588/588, zbt 0, m3te 23/23, game builds.
+- **2026-06-11 (prior)** — std.sx restructured to a pure re-export
+ facade (`49a36bb`): all implementations moved to std/core.sx /
+ std/fmt.sx / std/list.sx; std.sx = alias decls + namespace tail.
+ En route, two more issues filed AND resolved: 0121 fn aliases
+ (`721369a` — renamed aliases were broken for EVERY fn kind, not
+ just packs; scan-time fn_ast_map registration via the shared
+ alias-chain walk; example 0546) and 0122 ambient source-context
+ bugs in convergeClosureShapeSets / checkErrorFlow / unknown-type
+ loop (`340be40` — latent on master, exposed by the facade).
+ Probe-verified before executing: protocols (plain + Into xx path),
+ #builtin / #foreign aliases, reserved `string` (no alias needed or
+ possible). 37 .ir re-pins (pure renumbering). Gates: zbt 426/426,
+ suite 588/588, m3te 23/23, game builds + bundles.
+- **2026-06-11 (prior)** — Issue 0120 filed AND resolved (Agra-directed
+ same-session fix). Found probing the std.sx-as-pure-re-exports
+ restructure: generic-struct head alias (`BoxAlias :: Box;`) lowered
+ silently to `.unresolved` → LLVM backend panic; cross-module
+ `Box :: r.Box;` re-export invisible. Fix: `selectGenericStructHead`
+ follows const-alias decls hop-by-hop from each ALIAS AUTHOR's source
+ (`aliasedStructTemplate`, nominal.zig; `namespaceAliasVerdictFrom`
+ for `ns.X` RHS), checked before the template map so a facade's
+ same-name re-export beats an invisible global template; plus the
+ missing "unknown type" diagnostic on the `.call` type-head tail
+ (resolveTypeCallWithBindings). Also fixed PRE-EXISTING stale unit
+ test (calls.test.zig UFCS plan — predated a47ea14's opt-in model;
+ master was 425/426). specs.md Type Aliases + readme re-export
+ section + Decisions Log updated. Regression: examples/0211 (+rich/
+ +facade companions). Gates: zbt 426/426, suite 587/587.
+- **2026-06-11 (prior)** — BufAlloc.init by-value (`51194a2`, Agra
+ request): init no longer carves its state struct off the buffer's
+ head (`-> BufAlloc`, plain literal; the old `-> *BufAlloc` cost 24
+ bytes of every buffer and returned null under min-size). The
+ CLAUDE.md by-value convention now holds for ALL allocators.
+ Regression: examples/0839 (full-capacity 64+64 on a 128 buffer —
+ failed pre-fix; exact-fit, overflow, reset). 0129's pinned output
+ unchanged. .ir churn: init's signature (sret) + renumbering.
+ Gates: 586/586, zbt 0, m3te 23/23, game builds.
+- **2026-06-11 (earlier)** — Opt-in UFCS (`a47ea14`). Agra's model:
+ dot-calls opt-in via `:: ufcs (...)` marker or `:: ufcs target;`
+ alias; plain fns direct/`|>`-only. Parser (ufcs-fn form,
+ FnDecl.is_ufcs), call-plan + lowering gates (calls.zig,
+ lower/call.zig), protocol-receiver fall-through, generic dispatch
+ with receiver-bound `$T`, inferGenericReturnType → buildTypeBindings
+ (fixes pre-existing `T{}` mis-typing of structured-param generics).
+ 6 reliant examples migrated; mem helpers marked ufcs; specs §UFCS
+ rewritten; tests 0053+1166+0838. 585/585, zbt 0, m3te 23/23, game
+ builds. 0119 closed with the full arc in its banner.
+- **2026-06-11 (later)** — Phase 2.2 shipped (`84e0fb0`). Typed helpers
+ in std/mem.sx (create/destroy/alloc/free/clone/resize/mem_realloc,
+ era-complete bodies, no zero-init); bare malloc/free dropped from
+ std.sx (6 example files + game pieces.sx migrated to libc_*). The
+ 0119 "blocker" resolved as Agra's language ruling: generic free fns
+ are NOT dot-rewritten — fluent spelling is `|>` (parse-time desugar
+ → direct call → normal monomorphization; verified on protocol +
+ slice receivers). specs.md §UFCS corrected; 0119 RESOLVED banner.
+ Regression examples/0838 (direct + |> spellings; tracker 8/8).
+ 37 .ir re-pins (const-pool renumbering). Gates: 583/583, zbt 0,
+ m3te 23/23, game builds. String-clone deferred (string doesn't bind
+ []$T — known gap noted).
+- **2026-06-11** — Allocator primitive rename (`88bae3c`): protocol
+ `alloc`→`alloc_bytes`, `dealloc`→`dealloc_bytes` (2-method-era
+ signatures unchanged). Phase 4's naming piece pulled forward (Agra
+ Option A) so Phase 2.2 helpers land final-named once. Touched:
+ std.sx decl, mem.sx 6 impls, 4 library files, 13 examples (incl.
+ two custom Tracer impls — initially missed, caught by pre-pin
+ stdout review after the first --update captured their broken
+ output; restored, fixed, re-pinned), interp.zig thunk-name strings,
+ 37 .ir snapshots. Externals migrated + gated: game (SxChess.app
+ builds) + m3te (23/23). Suite 582/582, zbt 0. Discriminator note:
+ Obj-C `.alloc()` is zero-arg; Allocator `.alloc(size)` has an arg —
+ the sed keyed on `\.alloc\((?!\))`.
- **2026-05-25 (latest)** — `resolveType(null) → .s64` removed.
Signature changed to non-optional `*const Node`; 12 callers
surveyed and classified. The three unguarded ones — top-level