Registry-izes the two hooks that made stdlib namespaces and engine systems
compiler-hardcoded, so a package registers them with no compiler edit — the
Phase-1 prerequisite for shipping the controller libraries (#58–#61) as real
packages rather than in-repo stdlib.
- Engine systems are a data-driven registry (component, esys-fn, phase). The
core three (SpriteAnim/Motion — Update, Light2D — Render) are seeded in that
exact order, so uses_engine_systems / emit_engine_systems_for_phase are now
registry-driven with byte-identical output (verified: anim_ecs, light_ecs,
snake IR unchanged; 87/0 golden renders; C-free fixpoint holds). A package
appends with `@EngineSystem(Component, Phase)` on its esys function.
- Namespaces are a registry too: a package marks a provider with
`@Namespace(Foo)`, and emit_ns_call aliases an otherwise-unknown Foo.method to
the bare foo_method (the same generic path the core namespaces use) — after
every hardcoded core block, so core dispatch is untouched.
- Both annotations are keyword-free (like #64's @System), so no vocabulary /
grammar churn.
Proven end-to-end (hermetic, source path, runs everywhere): a package registers
Score + esys_score via @EngineSystem and coach_bonus via @Namespace; a consumer
game imports it and prints "4 99" — the engine system ran each Update and
Coach.bonus() dispatched, with no compiler edit for the package. Package suite
18/0.
Core stdlib namespaces stay on their optimized hardcoded blocks by design
(byte-identity + determinism); the generic path is proven to carry a namespace
and packages ride it.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>