Skip to content

First-run funnel: the REPL never teaches the commutative field calls, and the README buries the use case #548

Closed

Description

@ohohoreilly

Found by running the published quickstart cold on a clean machine, as a first-time visitor would.

The product works

docker run -it --rm ghcr.io/orlyatomics/orly repl connects and answers in ~2s (even on Apple Silicon, under emulation). *<['hits']>::(int) += 1 twice then a read gives 2, and set-union gives ["blue","green"] — upserting from the monoid identity with no new. The headline property is real and immediately demonstrable.

But the first thing a visitor tries fails

The REPL's own :help teaches assignment and read:

(true) effecting { new <['k']> <- 1; };  write through the pov
*<['k']>::(int);                         read it back

It never shows += or |= — the commutative field calls the project is pitched on, the first thing in the README, and the entire content of the announcement thread.

So the natural move is to take the help's write form and substitute the feature from the pitch:

orly> (true) effecting { <['counter']> += 5; };
2:37-2:56 [orly/type/add_visitor.h, 50]This expression is invalid.
orly> *<['counter']>::(int);
0

Three problems in four lines:

  1. The correct form needs a leading * and a ::(type) annotation, and nothing on the path says so.
  2. The diagnostic leaks an internal C++ header path and line number (orly/type/add_visitor.h, 50) with no explanation of what is invalid or how to fix it.
  3. The follow-up read returns 0 rather than an error, so it reads as "the write landed and the data is wrong".

The README compounds it

The announcement asked "how do I give my agents shared memory". The README opens with "a non-relational database built around Points of View, causally-ordered merge, and a compiled query language", and the first substantive paragraph is that the project was dormant from 2019. agent first appears meaningfully at line 167 of 250; the MCP server — the path that delivers value without learning orlyscript at all — is a parenthetical inside a Docker paragraph.

Scope

The first two are small and sit exactly on the path between "interesting post" and "aha". The last is a real diagnostics change and wants its own issue if picked up.


Status 2026-09-16. The first two shipped in #549. The multi-arch image (#552) turned into a
longer detour than expected: the arm leg of the docker build was blamed in turn on memory
pressure, on QEMU, and on aarch64 LTO codegen being ~18x slower. All three were wrong. It was a
genuine bug — orlyc deadlocking on aarch64 (#554), a fiber reading a cached thread pointer
after migrating OS threads, fixed in #555.

With that in, the arm64 image job is 9m48s end to end, faster than amd64's 12m04s, every smoke
included. There was never anything slow about aarch64 here.

The fourth item is now #557: Base::AsStr(code_location, message) in orly/error.h bakes the
C++ TCodeLocation into the exception message, so every consumer inherits it — both orlyc's
stderr and the WS reply the REPL and MCP server read.

2026-09-16: #552 merged. Worth being precise about what that does and does not do. The
workflow builds both arches natively and runs every smoke on each, but docker.yml only
publishes on a v* tag or a manual dispatch — a push to master triggers nothing. So
ghcr.io/orlyatomics/orly:latest is still the amd64-only image from two months ago, and Apple
Silicon still gets the platform-mismatch warning on the headline command until the next tagged
release (or a deliberate dispatch). The box above is ticked for the work; the user-visible
symptom that opened this issue clears at publish.

Activity

  1. ohohoreilly commented on Sep 17, 2026

    @ohohoreilly
    MemberAuthor

    Published, and the symptom is gone

    docker.yml dispatched on master: both arches built natively, every gate ran on each image (MCP smoke, in-container orlyc compile, REPL mode), and :latest was stitched into a real manifest list.

    $ docker buildx imagetools inspect --raw ghcr.io/orlyatomics/orly:latest
      "mediaType": "application/vnd.docker.distribution.manifest.list.v2+json",
      ... "platform": { "architecture": "amd64", "os": "linux" }
      ... "platform": { "architecture": "arm64", "os": "linux" }
    

    And the thing this issue was actually about — the README's headline command, run on an Apple Silicon machine, no --platform, nothing special:

    $ docker pull ghcr.io/orlyatomics/orly:latest
    $ docker image inspect ... --format '{{.Os}}/{{.Architecture}}'
    linux/arm64
    
    $ printf '40 + 2;\n:quit\n' | docker run -i --rm ghcr.io/orlyatomics/orly:latest repl
    orly-repl: connected to ws://127.0.0.1:8082/
    pov 43532f2c-bb01-8f87-60fa-3f1f6050218e (private, new); :help for help
    orly> 42
    

    No platform-mismatch warning, no emulation. Closing on that rather than on the merge.

    Two things the publish turned up

    The manifest verification was broken and failed the very run it was meant to protect. It grepped '"architecture":"[a-z0-9]+"' against imagetools inspect --raw, which pretty-prints — the bytes are "architecture": "amd64", with a space — so it matched nothing while the manifest it was checking was perfectly correct. It had never executed before, because that job only runs on a dispatch or a v* tag and neither had ever happened. #559 replaces the grep with a jq parse, checked in both directions against the live registry.

    The arm REPL smoke flaked once, on the first dispatch: connected, took a pov, then 29 seconds of silence and orly: websocket closed. It passed on the immediate re-run, passed on #552's own run the day before, and passes locally against the published arm image — so 1 in 4, not a regression. Worth knowing that the job's Container logs (for diagnosis) step cannot see it either way: it tails the long-lived orly container from the MCP smoke, while the REPL step starts its own ephemeral docker run --rm. If that flake recurs, fixing the diagnostic is the first move.

    Remaining scope

    Nothing here. The fourth item went to #557 (compiler diagnostics leaking internal C++ paths), which is unrelated to the first-run funnel except that the funnel is where it was noticed.

    Note this publishes :latest only. The repo still has no v* tags, so there is no versioned image — a deliberate choice, not an oversight, and a separate decision from this issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions