Skip to content

fix(onboarding): install vendor/ on first make up/upd so a fresh clone boots - #64

Merged
laugiov merged 2 commits into
mainfrom
claude/fresh-clone-onboarding-rhmlps
Aug 18, 2026
Merged

fix(onboarding): install vendor/ on first make up/upd so a fresh clone boots#64
laugiov merged 2 commits into
mainfrom
claude/fresh-clone-onboarding-rhmlps

Conversation

@laugiov

@laugiov laugiov commented Aug 18, 2026

Copy link
Copy Markdown
Owner

Pipeline: chore
Spec: n/a — no application code changed
Gates: no gate report — see "Factory pipeline" below, the /factory-bug run halted at step 1 and escalated
Deploy-impact: make up and make upd now depend on a new ensure-vendor target. On a host where backend-symfony/vendor/autoload_runtime.php already exists it is a single test -f and nothing else runs. On a host where it is missing, the first make up/upd runs one extra docker compose run --rm --no-deps backend-dev composer install before starting the stack, so that first start is several minutes longer. No image, compose file or environment template is touched, and nothing changes for docker compose up invoked directly — which is what CI and every deployment path use.

Summary

An external user followed docs/08_getting_started.md on a fresh clone (GitBash on
Windows) and the documented health check failed:

$ curl -s http://localhost:8081/healthz
Fatal error: Uncaught Error: Failed opening required
'/app/vendor/autoload_runtime.php' in /app/public/index.php:5

The backend-dev anchor in docker-compose.yml bind-mounts ./backend-symfony:/app,
which shadows the vendor/ tree the Dockerfile builds into the image. vendor/ is
gitignored, so a fresh host clone has none and public/index.php cannot boot. The
anchor is inherited by backend-test, backend-e2e, backend-preprod, scheduler
and canary-worker.

make quickstart already handled this — it creates and chmods backend-symfony/vendor,
then runs composer install once the stack is up — so the README path worked and only
the manual path in docs/08_getting_started.md was broken.

The bind mount is deliberately left alone. It is what makes local edits visible
without a rebuild. The fix populates vendor/ on the host instead.

Reported in GitHub Discussions; there is no issue number to close.

Changes

  • Makefile — new ensure-vendor target, a prerequisite of up and upd. Guarded
    on backend-symfony/vendor/autoload_runtime.php, so once vendor/ is populated the
    normal path costs one test -f and is otherwise unchanged. It creates and chmods
    vendor/, var/ and public/bundles/ first — the image runs as USER 10001 and
    cannot write into a host-owned directory it did not create — and uses
    docker compose run --rm --no-deps so postgres and redis are not started for a
    composer install. public/bundles is included because the composer auto-scripts
    run assets:install %PUBLIC_DIR%; quickstart chmods it for the same reason.
  • docs/08_getting_started.md — the curl /healthz check moves from section 2 to
    section 3, after make composer-install. Section 2 gains a note explaining why the
    backend cannot answer before dependencies are installed, and Troubleshooting gains an
    entry keyed on the literal autoload_runtime.php error string.
  • scripts/doctor.sh — a BACKEND DEPENDENCIES check for
    vendor/autoload_runtime.php pointing at make composer-install. It runs before
    CONNECTIVITY because a missing vendor/ presents as a container that is up with
    every port answering while /healthz returns a PHP fatal.
  • factory/found-issues.md — entry chore(deps): bump recharts from 3.8.0 to 3.8.1 in /frontend-react #9, logged and not fixed (see below).

make quickstart is untouched. docker-compose.yml, docker-compose.prod.yml and
docker-compose.demo.yml are untouched.

Factory pipeline

/factory-bug was run and halted at step 1 on its own rule: "If the reproduction
cannot be written, stop and escalate."

The reproduction cannot be committed. The only automated suites are PHPUnit and Vitest,
and they run inside the container: make test invokes vendor/bin/phpunit
(Makefile:218), make stan invokes vendor/bin/phpstan (:221). A missing vendor/
is precisely the state to reproduce, so the test harness does not exist in that state.
A PHPUnit test asserting Makefile content would only ever run where the bug is absent
and could never be seen red in CI, which the constitution's testing rules require.
Building a shell/Make harness plus the CI job to run it is a design decision — a
/factory-feature, not a bug fix. That gap is logged as factory/found-issues.md #9.

The constitution also scopes the pipelines to backend-symfony/ and frontend-react/;
this diff touches neither. Hence Pipeline: chore, which docs/factory/pipelines.md
describes exactly: "process, documentation or CI only — changes no application code."

Reproduction evidence (out of tree)

The red output the bug pipeline requires, produced with a stub docker and the
Makefile taken from main and from this branch. Not committed — it has no place
in the repository without the CI job that would run it.

################ RED — main ################
    docker compose up -d
FAIL: backend-symfony/vendor/autoload_runtime.php is MISSING after 'make upd'
      -> public/index.php:5: Failed opening required '/app/vendor/autoload_runtime.php'
exit=1

################ GREEN — this branch ################
    docker compose run --rm --no-deps backend-dev composer install --no-interaction --no-progress
    docker compose up -d
PASS: backend-symfony/vendor/autoload_runtime.php exists after 'make upd'
exit=0

--- second 'make upd' on a populated vendor/ ---
    docker compose up -d
PASS: composer install did NOT run again

make doctor was run both ways: it reports the check green with the file present, and
fails with exit 1 and the actionable message without it.

Escalation triggers

Every trigger in factory/gates.yaml was evaluated. None fired.

Trigger Result
sensitive_paths not fired — docker-compose*.yml and infra/docker/** are sensitive and were deliberately not touched; Makefile, docs/ and scripts/doctor.sh are not on the list
migration_present not fired
public_api_changed not fired
new_dependency not fired
large_diff not fired — 77 changed lines against a 400 limit
adversarial_not_converged not evaluated — the pipeline halted before fix_to_pr, so no adversarial iteration ran

Objections

ADVISORY ; out-of-tree reproduction ; No committed test guards this regression
ADVISORY ; Makefile:69 ; composer auto-script cache:clear runs without postgres under --no-deps and was never executed
ADVISORY ; factory/found-issues.md#9 ; No pipeline can carry a defect in the build and onboarding tooling

In a pipeline with no spec, the only route to BLOCKING is a failing executable test, so
these are ADVISORY by construction rather than by judgement.

Reviewer note — what was not verified

There was no Docker daemon in the environment this branch was built in, so make test,
make stan and make cs-fixer were not run
. The diff contains no PHP, no JS and no
composer or npm manifest change, so none of them has anything to act on — but that is a
prediction, not a result, and the checklist below is left unticked accordingly.

The one behaviour worth a real run before merge: ensure-vendor invokes composer install
with --no-deps, so the auto-scripts (cache:clear, assets:install) execute with
postgres down. Doctrine connections are lazy and this is the ordinary Symfony case, but it
was not executed here. A make upd on a clone with no backend-symfony/vendor is the
check that matters.

Type of Change

  • Bug fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change that adds functionality)
  • Refactoring (no functional change)
  • Documentation update
  • Infrastructure / CI change

Checklist

  • make test passes — not run, no Docker daemon available; no PHP in the diff
  • make stan passes — not run, same reason; no PHP in the diff
  • make cs-fixer applied and left the worktree unchanged — not run, same reason
  • New code has tests — no, and deliberately: see "Factory pipeline" above
  • Documentation updated if needed
  • No secrets or credentials in the code
  • Follows DDD architecture (controllers delegate to handlers) — n/a, no application code

Factory gates

  • Every commit and task cites a requirement id (feature pipeline) — n/a, chore
  • Gate reports linked in the Gates: line above — none exists, stated instead
  • Escalation triggers listed in the gate report, including the ones that did not fire
  • For a bug or security PR: the reproduction or exploit test is committed before the fix — n/a as chore; the red output is in this description and the reason it is not committed is stated

🤖 Generated with Claude Code

https://claude.ai/code/session_015GM8iTi632qrwApx8KMdfw


Generated by Claude Code

claude added 2 commits August 18, 2026 06:43
A fresh clone that follows docs/08_getting_started.md hit a PHP fatal on
the documented health check:

  Fatal error: Uncaught Error: Failed opening required
  '/app/vendor/autoload_runtime.php' in /app/public/index.php:5

The backend-dev anchor bind-mounts ./backend-symfony over /app, which
shadows the vendor/ tree the image builds in. vendor/ is gitignored, so
on a fresh host clone there is nothing behind the mount and index.php
cannot boot. The mount stays — it is what makes local edits visible
without a rebuild — so the fix is to populate vendor/ on the host.

- Makefile: new `ensure-vendor` target, a prerequisite of `up` and
  `upd`. Guarded on vendor/autoload_runtime.php, so once vendor/ is
  populated it costs one `test -f` and the normal path is unchanged. It
  creates and chmods vendor/, var/ and public/bundles/ first (the image
  runs as USER 10001 and cannot write into a host-owned directory it did
  not create), and uses `docker compose run --rm --no-deps` so postgres
  and redis are not started just for a composer install.

- docs/08_getting_started.md: the healthz check moves from section 2 to
  section 3, after `make composer-install`, with a note explaining why
  the backend cannot answer before dependencies are installed, plus a
  troubleshooting entry for the exact error message.

- scripts/doctor.sh: new BACKEND DEPENDENCIES check for
  vendor/autoload_runtime.php, pointing at `make composer-install`. It
  runs before CONNECTIVITY, because a missing vendor/ presents as a
  container that is up with every port answering while /healthz returns
  a PHP fatal.

`make quickstart` already handled this and is untouched. CI calls
`docker compose up` directly, never `make up`/`make upd`, so no job
changes behaviour.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015GM8iTi632qrwApx8KMdfw
Running /factory-bug on the fresh-clone vendor/ failure surfaced a gap in
the factory itself, not in the change under test: no pipeline can carry a
defect that lives in the build and onboarding tooling.

The bug pipeline requires a reproduction test committed before the fix and
seen red. The only automated suites run inside a container that needs
vendor/ to exist, which is exactly what this class of bug removes, so the
test harness is absent in the state that has to be reproduced. Logged, not
fixed: building such a harness is a design decision and belongs in its own
feature run.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015GM8iTi632qrwApx8KMdfw
@laugiov
laugiov merged commit 7945294 into main Aug 18, 2026
16 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants