The ORCH-058 staging rebuild (check_staging_image_fresh) builds the image with
the task git-worktree as the docker build context. A fresh worktree holds only
tracked files, but the Dockerfile did `COPY data/ ./data/` — and `data/` (the
SQLite dir) is gitignored, so it is absent from that context: `docker build`
failed with exit 1 ("BUILD-STAGING: docker build failed - aborting"), bouncing
the task off deploy-staging back to development in a loop.
The COPY was dead weight regardless: `data/` is always supplied at runtime as a
bind-mount volume (./data:/app/data, see docker-compose.yml) which shadows
anything baked into the image. Replace it with `RUN mkdir -p /app/data` so the
mountpoint exists without depending on the build context.
Regression guard: test_tc08b_dockerfile_does_not_copy_gitignored_data_dir
forbids COPY of any gitignored path (the worktree-context invariant).
Refs: ORCH-021
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Per ADR-001 step 3 / AC-4: after the freshly rebuilt staging container is
healthy, run staging_check.py --mode stub against the fresh 8501 stand BEFORE
reporting success, so the EXACT artefact BUILD-ONCE retagged to prod is the one
validated on staging. Fail-closed: staging_check rc!=0 -> exit 1 (not promoted).
- Invoked inside the container (docker exec $TARGET_SERVICE) per the canonical
signature in scripts/staging_check.py header, --base-url http://localhost:$TARGET_PORT.
- Targets ONLY 8501 (staging), never 8500 (prod) - AC-9.
- --mode stub: fast, deterministic, no LLM spend (ADR).
- Static regression test test_tc07_build_staging_runs_staging_check_stub_after_health:
asserts staging_check.py + --mode stub present, runs after health, before exit 0,
fail-closed, and never hard-codes prod 8500.
Closes reviewer P0/P1 (ORCH-058 attempt 3): the committed --build-staging hook
recomputed GIT_SHA=$(git rev-parse HEAD) in $REPO (prod clone on `main`) and built
`docker build ... "$REPO"`, ignoring the caller-supplied BUILD_CONTEXT/GIT_SHA. On
the deploy-staging -> deploy edge the PR is not yet merged, so `main` HEAD != the
validated SHA -> the staging image got the wrong revision label and Strategy-B's
guard fail-closed on EVERY valid self-deploy (AC-6 deadlock). It also only did
`docker build` + exit 0 — never recreating 8501 nor health-checking — so
rebuild_staging_image's rc=0 ("rebuilt and healthy") was a lie (AC-4 unmet).
- Hook --build-staging now honours caller BUILD_CONTEXT (validated worktree) and
GIT_SHA, recreates orchestrator-staging on the fresh image and runs the 10x6s
health-check; build/health failure -> exit 1 (FAILED contract preserved).
- image_freshness.rebuild_staging_image: document why COMPOSE_PROFILE/TARGET_SERVICE/
TARGET_PORT are intentionally omitted (hook STAGING defaults -> 8501 only, P2).
- tests: assert the caller<->hook contract (builds from $BUILD_CONTEXT, no
`git rev-parse HEAD` recompute, recreates + health-checks 8501) so the P0
regression can't pass green again (P1).
Refs: ORCH-058
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>