Commit graph

6 commits

Author SHA1 Message Date
8fed9add66 refactor(x): per-process scratch dirs, Ludic ports of the LSP test and Forgejo release
- every scratch file lives in `$TMPDIR/x_<pid>/` (tmp_dir/tmp_path in
  prelude.ludic), removed by main's new dispatch() → tmp_cleanup();
  X_KEEP_TMP=1 keeps it. `x test` and `x check-*` may now run together.
- `x test-lsp` (tools/x/lsp_test.ludic) replaces tools/test-lsp.py: the
  whole request stream is framed into one stdin file, the server runs to
  `exit`, and the response stream is parsed back by request id; adds a
  check that ludicc's own error is published on save
- tools/x/forgejo.ludic replaces tools/ci/forgejo_release.py (curl with a
  0600 header file; the token is no longer on the command line;
  LUDIC_FORGEJO_API for forks)
- `x docs-palette --check` regenerates into scratch and compares, so the
  drift guard judges the working tree rather than git HEAD; the generator
  no longer emits a trailing blank line the formatter rejects
- `x test-tools`: exit 2 from test-lsp / test-grammar.js is a visible
  skip, never a pass; the widget-prop test uses the `id: Root` syntax
- tools/test-grammar.js: current vocabulary (property/model/handler/
  prefab/scene/event/become/@Queries), LUDIC_NODE_MODULES, exit 2 on skip
- tools/atlas.ludic rewritten in the current language (it did not compile)
- operators.ludic / os.ludic registered in the suite
- json.ludic: j_quote() writer helper

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-05 01:12:26 +03:00
7cbd5d175c feat(compiler): package-declarable engine systems + namespaces (#62)
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>
2026-09-01 12:30:01 +03:00
075a7b1430 feat(pkg): x build-lib / prebuilt consumption — binary packages end-to-end (#64)
All checks were successful
bootstrap / cfree-fixpoint (push) Successful in 19s
ci / build-and-test (push) Successful in 1m37s
commit-lint / conventional-commits (push) Successful in 1s
docs / build-and-deploy (push) Successful in 26s
The package-manager half of prebuilt binary packages, on top of the compiler
foundation (dynamic system registration + --emit-module).

- x build-lib [module.ludic]: compile a package's module to a per-target native
  dylib under lib/<target>/, with an @rpath install name so a consumer resolves
  it from the content-addressed store.
- x link-flags: print the clang flags (the dylib, an rpath to its store dir,
  -export_dynamic) so any build system links a project's prebuilt module dylibs;
  x app splices them automatically for in-repo builds.
- kind prebuilt is resolved + linked like any dependency; a missing build target
  stays a hard error.

Proven hermetically (macOS-gated, since dylibs are native): a module exporting a
component + an @System(Update) + a function is built with x build-lib, fetched
as a prebuilt dep, and linked into a consumer game that never saw its source —
the module's system mutates the shared world and its function is callable
("3 42"). Package suite 17/0; full suite 87/0.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-01 07:52:06 +03:00
035e6dfe41 test(pkg): a consumer game uses a package's component, model, system + fn
All checks were successful
bootstrap / cfree-fixpoint (push) Successful in 18s
ci / build-and-test (push) Successful in 1m35s
commit-lint / conventional-commits (push) Successful in 2s
docs / build-and-deploy (push) Successful in 25s
Locks in the source-package guarantee: because Ludic is AOT, a package's
property (component), model, @OnSpawn handler (system) and plain function all
compile into the consumer's compile-time ECS with no ABI seam. The new case
fetches such a package and runs a game that spawns the imported model, reads the
imported component via reflection, relies on the imported system, and calls the
imported function — asserting "50 7".

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-01 07:19:08 +03:00
7c868585de test(pkg): assert re-fetch heals a tampered store entry
All checks were successful
bootstrap / cfree-fixpoint (push) Successful in 17s
ci / build-and-test (push) Successful in 1m33s
commit-lint / conventional-commits (push) Successful in 2s
docs / build-and-deploy (push) Successful in 26s
The content-addressed store keys an entry by its hash-named directory, so
`x get` trusts one that already exists and will not silently overwrite it.
The tamper check now drops the entry before re-fetching and asserts `x verify`
goes green again, rather than relying on a no-op restore.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-01 07:13:09 +03:00
2c44bae496 feat(pkg): package manager — fetch + MVS resolve + namespace registration (#63)
All checks were successful
bootstrap / cfree-fixpoint (push) Successful in 17s
ci / build-and-test (push) Successful in 1m33s
commit-lint / conventional-commits (push) Successful in 2s
docs / build-and-deploy (push) Successful in 25s
Implements the v1 direction decided in the RFC as a set of `x` subcommands
plus a small, contained compiler change.

  * URL-as-identity, no registry — a dependency is named by its git import
    path and a `git tag vX.Y.Z` publishes a version.
  * Minimum Version Selection — a `require` is a minimum; the resolver picks
    the greatest required minimum per module, then the reachable closure at
    those versions. Deterministic, no SAT solver (tools/x/pkg.ludic).
  * Content-addressed global store + per-project links — packages live once in
    ~/.ludic/store keyed by a content hash; each project links them under
    ludic_modules/. package.ludic (manifest) + package.lock.ludic (lock).
  * Namespace registration for source packages via a module-root import
    fallback in the compiler: do_import resolves a non-local, non-absolute
    import under $LUDIC_MODULES (default ludic_modules/), so a fetched
    package's Ludic compiles into the consumer the way the built-in stdlib
    does. Collisions and missing prebuilt targets are hard errors.

Commands: x add / x get / x update / x verify / x vendor. New hermetic suite
`x test-pkg` (stands up throwaway git repos, offline) is gated inside `x test`.

Existing programs compile byte-for-byte identically (the import fallback only
fires when the local path is absent); the C-free bootstrap fixpoint holds and
the seed is regenerated. Full suite: 87 passed, package suite: 12 passed.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-01 07:08:12 +03:00