diff --git a/CHANGELOG.md b/CHANGELOG.md index 210a582..526bbf9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ three commits past it), and a bug report can name a release instead of a sha nob Sections dated before 2026-09-19 predate the cycle and stay as they are. ## Unreleased +- fix(doctor, test-stack-up): **in a cloud container, a missing Docker daemon is now reported as normal, with the Docker-free route, instead of a warning that says to start it.** The Claude Code on the web container has the docker CLI but no daemon, and the agent cannot start one. Doctor used to WARN "docker daemon is not responding … sudo systemctl start docker", so sessions tried, failed, and reported "cannot start the docker daemon" as a blocker, until the user said to use `mxcli run --local`. Now the cloud lane prints: no Docker here, normal, do not try to start it; build check = exec.sh's mxbuild gate; run the app = `./mxcli run --local`. On a desktop (Docker or Podman, stopped or absent) the warning and start hint stay, plus one line saying a container is optional: the mxbuild gate needs none, and Studio Pro's Run Locally or `mxcli run --local` runs the app. The no-runtime text no longer says the build check needs Docker. `test-stack-up.sh` with the app down and no reachable Docker/Podman now stops with the Docker-free route instead of failing inside `mxcli docker run`. — MendixMau - fix(gate-check): **the stage-decision readers now read only the Decisions table, and Stage 7 accepts a dated CONFIRMED.** `has_confirmed_decision` (Stages 3 and 4) and the Stage 7 cutover check scanned every pipe row in the register, so an Open-questions row numbered 4 or 7 with Status CONFIRMED passed that stage with no decision behind it. Both now count only rows under a header whose first cell is `Stage`; a register with no such header keeps the old every-row scan. Stage 7 also matched the status string-exactly, so `CONFIRMED 2026-08-10` failed there while passing every other stage (TD-07); it now uses the same word-anchored match. Positive control: the pre-fix script passes Stages 4 and 7 on an Open-questions-only register and fails Stage 7 on the dated status. Fixture T13–T15 in `test-bug03-gates.sh` — MendixMau - learn(bug-logs): **`BUG-DRAFT-grant-association-generalization-member`** — a member association owned by another module's entity cannot be named in a `grant` statement, so `revoke` + `re-grant` silently drops that member access and `mx check` reports CE0066; patch-only workaround provided. Found fixing a guest-groups association in a Mendix app (mxcli v0.23.0, Mendix 11.12.2). — MendixMau - chore(inbox): **triage of `contrib/inbox/`: removed 15 promoted/obsolete files, gave the rest neutral names and scrubbed identifiers.** Gone: the ten machine-diff `*-patches.md` files from 2026-09-14, the 2026-09-27 field-project patch file, the built company-brain idea, and three already-promoted or superseded bug dumps. Kept for now: `2026-09-27-mxcli-upstream-issues.md`, because five drafts under `bug-logs/pending-github-issues/` cite it as their source. Four remaining files were renamed to `field-project-{a,b,c}` names; project and app names, home-style paths and personal names inside the 17 remaining entries were replaced with neutral labels or placeholders (technical content unchanged). — MendixMau diff --git a/bin/doctor.sh b/bin/doctor.sh index 65935b2..51519f6 100755 --- a/bin/doctor.sh +++ b/bin/doctor.sh @@ -764,6 +764,20 @@ container_start_hint() { esac fi note "Then re-run: bin/doctor.sh${PROJECT_DIR:+ $PROJECT_DIR} (this section is skipped by --quick)" + note "Not required, if you would rather not run one: the build check (exec.sh's mxbuild gate) needs no" + note "container, and Studio Pro's Run Locally or ./mxcli run --local runs the app without one." +} + +# cloud_no_daemon — the Claude Code on the web container ships the docker CLI but no running +# daemon, and the agent cannot start one there. Telling it "sudo systemctl start docker" sent +# sessions off trying, then reporting "cannot start the docker daemon" as a blocker — while the +# mxbuild gate (exec.sh) and `mxcli run --local` both work with no Docker at all. So in the cloud +# lane a missing daemon is reported as the normal state, with the Docker-free route, not a WARN. +cloud_no_daemon() { + ok "no $RUNTIME_LABEL in this cloud container — normal here, and not a blocker. Do not try to start it." + note "Build check: exec.sh's mxbuild gate — mxbuild is a plain binary, no Docker needed." + note "Run the app: ./mxcli run --local (add --hub for a preview URL) — skills/cloud-dev-environment.md." + note "Snapshot first: mxcli run --local consolidates a split-model .mpr (bug-logs, CRITICAL)." } if [ "$NO_DOCKER" = 1 ]; then @@ -774,7 +788,12 @@ elif [ -n "$CONTAINER_RUNTIME" ]; then container_daemon_up || DOCKER_STATE=$? case "$DOCKER_STATE" in 0) - ok "$RUNTIME_LABEL responding — mxcli docker check + test-stack-up.sh (app up, e2e, screenshots) available" ;; + ok "$RUNTIME_LABEL responding — mxcli docker run + test-stack-up.sh (app up, e2e, screenshots) available" ;; + *) [ "$ENV_LANE" = cloud ] && DOCKER_STATE=cloud ;; + esac + case "$DOCKER_STATE" in + 0) ;; + cloud) cloud_no_daemon ;; 2) warn "$CONTAINER_RUNTIME is installed but '$CONTAINER_RUNTIME info' gave no answer within ${DOCKER_PROBE_SECS} s — treated as not running." note "That silent wait is what makes a setup look hung. Raise the bound with" @@ -790,19 +809,20 @@ elif [ -n "$CONTAINER_RUNTIME" ]; then # Never elsewhere — Windows launch paths vary and Linux needs sudo. Podman is left alone: # `podman machine start` on a machine that has never run `podman machine init` is not a safe # guess to make on someone's behalf. - if [ "$DOCKER_STATE" != 0 ] && [ "$INSTALL" = 1 ] && [ "$CONTAINER_RUNTIME" = docker ] && [ "$PLATFORM" = macos ] && [ -d /Applications/Docker.app ]; then + if [ "$DOCKER_STATE" != 0 ] && [ "$DOCKER_STATE" != cloud ] && [ "$INSTALL" = 1 ] && [ "$CONTAINER_RUNTIME" = docker ] && [ "$PLATFORM" = macos ] && [ -d /Applications/Docker.app ]; then if open -a Docker 2>/dev/null; then note "--install: launched Docker Desktop (open -a Docker). Give it ~30-90 s, then re-run doctor." fi fi +elif [ "$ENV_LANE" = cloud ]; then + cloud_no_daemon else warn "no container runtime found — neither docker nor podman. One is recommended for new builders." - note "It is what lets the agent verify its own build: 'mxcli docker check' (deep model+build" - note "verification) and project-bin/test-stack-up.sh (Postgres + the app up, Playwright e2e," - note "page screenshots) both need it. Without it, only mxbuild verifies the model and a human" - note "must open Studio Pro to see whether anything actually renders." - note "No-container fallback for just running the app: 'mxcli run --local' against a native" - note "PostgreSQL (host:PORT)." + note "The build check does NOT need it: exec.sh's mxbuild gate is a plain binary. What it adds" + note "is the running app in a container: project-bin/test-stack-up.sh (Postgres + the app up," + note "Playwright e2e, page screenshots)." + note "No-container route for running the app: 'mxcli run --local' against a native" + note "PostgreSQL (host:PORT) — the same route the cloud lane uses." note "Docker Desktop needs a paid licence at larger companies, and is NOT required: Podman is" note "the licence-free option (docker-CLI compatible; doctor probes it directly, so no docker" note "shim is needed). Rancher Desktop and colima (macOS) are the other common substitutes." diff --git a/project-bin/test-stack-up.sh b/project-bin/test-stack-up.sh index 124b6f3..8d1a0b0 100755 --- a/project-bin/test-stack-up.sh +++ b/project-bin/test-stack-up.sh @@ -320,7 +320,28 @@ fi # --- Bring up the app ------------------------------------------------------- if [ $APP_FOUND -ne 0 ]; then if [ "$MODE" = "nodocker" ]; then - bad "App down and --no-docker given. Click Run Locally in Studio Pro, then re-run --check." + bad "App down and --no-docker given. Click Run Locally in Studio Pro (or, with no Studio Pro, ./mxcli run --local), then re-run --check." + exit 1 + fi + # No reachable Docker (or Podman) daemon: say so and name the Docker-free route, instead of letting + # `mxcli docker run` fail with a daemon error the agent then reports as "cannot start Docker". + # A cloud container ships the docker CLI with no daemon; that is normal, not a blocker. + # Bounded: a stopped Docker Desktop can leave `docker info` silent for minutes. + _RT=docker; command -v docker >/dev/null 2>&1 || _RT=podman + if ! command -v "$_RT" >/dev/null 2>&1; then _DK=1; else + "$_RT" info >/dev/null 2>&1 & _dk_pid=$!; _dk_w=0; _DK= + while kill -0 "$_dk_pid" 2>/dev/null; do + [ "$_dk_w" -ge 15 ] && { kill "$_dk_pid" 2>/dev/null; _DK=2; break; } + sleep 1; _dk_w=$((_dk_w + 1)) + done + [ -n "$_DK" ] || { wait "$_dk_pid"; _DK=$?; } + fi + if [ "$_DK" != 0 ]; then + bad "App down and no Docker/Podman reachable, so this script cannot build the app container." + echo " Normal in a cloud container, and fine on a desktop without one. Run the app without it:" + echo " Studio Pro: Run Locally. No Studio Pro:" + echo " ./mxcli run --local -p $(basename "$MPR") # flags: skills/cloud-dev-environment.md" + echo " Snapshot first — mxcli run --local consolidates a split-model .mpr. Then re-run with --check." exit 1 fi if [ -z "$MXCLI" ]; then diff --git a/tests/wave2/test-doctor-docker-probe.sh b/tests/wave2/test-doctor-docker-probe.sh index 5843dfb..4da3c1b 100755 --- a/tests/wave2/test-doctor-docker-probe.sh +++ b/tests/wave2/test-doctor-docker-probe.sh @@ -29,7 +29,9 @@ echo "doctor docker probe — $DOCTOR" # 1. hanging daemon: bounded, and says so S0=$(date +%s) -PATH="$T/hang:$PATH" MXTK_DOCKER_PROBE_SECS=2 bash "$DOCTOR" > "$T/hang.out" 2>&1 +# Cases 1-2 are the desktop/devcontainer lanes: CLAUDE_CODE_REMOTE cleared, so the fixture +# means the same thing when it runs inside a cloud session. Case 2b is the cloud lane. +PATH="$T/hang:$PATH" CLAUDE_CODE_REMOTE= MXTK_DOCKER_PROBE_SECS=2 bash "$DOCTOR" > "$T/hang.out" 2>&1 S1=$(date +%s) if [ $((S1 - S0)) -lt 40 ]; then ok "hanging docker: doctor finished in $((S1 - S0)) s (bound 2 s)"; else fail "hanging docker: doctor took $((S1 - S0)) s — the bound is not biting"; fi assert_contains "$T/hang.out" "probing the docker daemon (bounded: 2 s" "hanging docker: announces the probe and its bound before waiting" @@ -39,10 +41,19 @@ assert_contains "$T/hang.out" "Then re-run: bin/doctor.sh" "hanging docker: says assert_missing "$T/hang.out" "docker daemon responding" "hanging docker: not reported as up" # 2. daemon down, answering at once -PATH="$T/down:$PATH" bash "$DOCTOR" > "$T/down.out" 2>&1 +PATH="$T/down:$PATH" CLAUDE_CODE_REMOTE= bash "$DOCTOR" > "$T/down.out" 2>&1 assert_contains "$T/down.out" "daemon is not responding" "down docker: reported as not responding" assert_contains "$T/down.out" "To start it:" "down docker: carries a start command" assert_missing "$T/down.out" "gave no answer within" "down docker: a fast 'down' is not called a timeout" +assert_contains "$T/down.out" "Not required, if you would rather not run one" "down docker: says a container is optional" + +# 2b. cloud container: docker CLI, no daemon — the normal state there, never a start command. +# (Sessions told "sudo systemctl start docker" tried, failed, and reported it as a blocker.) +PATH="$T/down:$PATH" CLAUDE_CODE_REMOTE=true bash "$DOCTOR" > "$T/cloud.out" 2>&1 +assert_contains "$T/cloud.out" "normal here, and not a blocker" "cloud, no daemon: reported as normal" +assert_contains "$T/cloud.out" "mxcli run --local" "cloud, no daemon: names the Docker-free run route" +assert_missing "$T/cloud.out" "To start it:" "cloud, no daemon: no start command" +assert_missing "$T/cloud.out" "WARN docker is installed" "cloud, no daemon: not a WARN" # 3. daemon up PATH="$T/up:$PATH" bash "$DOCTOR" > "$T/up.out" 2>&1