Split out of #15, which fixed the root .editorconfig and .gitignore but could
not satisfy its third bullet without breaking both image builds. Filed so the
residual work survives #15 being closed by PR #35.
Problem
The org model .dockerignore starts with .git; this repo's does not, so every docker build ships the full git history into the build context.
It cannot simply be added today. Both images read git metadata at build time, as
of main at fbfe1df:
Backend.Dockerfile.backend:12 is COPY .git /repo/.git, present so
that backend/Makefile's VERSION := $(shell git describe --always --dirty)
resolves. With .git in .dockerignore the COPY has no source and the
build fails outright.
Frontend.Dockerfile does COPY . . then RUN make check, whose test
step is the production vite build. vite.config.js lines 5-6 run execSync("git rev-parse --short HEAD") and execSync("git rev-parse HEAD")
at config-eval time, so Vite throws before transforming any module. The
frontend does not COPY .git explicitly — it gets .git incidentally via COPY . ., which is exactly why adding the ignore entry breaks it.
#17 covers the backend half: its definition of done already requires removing COPY .git /repo/.git and driving the version from ARG VERSION instead. It
does not cover the frontend vite.config.js coupling, and neither issue owns
the .dockerignore line itself. That gap is what this issue is for.
Definition of done
vite.config.js no longer shells out to git at config-eval time in a
Docker build. Take the commit hash from an env var or build arg with a
fallback (so a missing .git degrades to a placeholder instead of throwing),
and pass it through from Dockerfile.
Dockerfile.backend no longer needs .git — either land #17 first, or
confirm it has landed, rather than duplicating that change here.
.dockerignore has .git as an entry.
docker build . succeeds and the built page still shows a commit hash
(not a crash, not an empty string where a hash is expected).
docker build -f Dockerfile.backend . succeeds and the binary still
reports a sensible version.
Root make check and cd backend && make check both pass.
TODO.md updated in the same commit.
Commit title ends with (closes #N).
Implementation requirements
Sequence after #17, or coordinate with it — do not re-do the backend Dockerfile
rework in this issue.
Leave the .claude entry in .dockerignore alone; that is #28's scope.
make targets and script/ entrypoints only for verification.
No attribution trailers in the commit message.
Split out of #15, which fixed the root `.editorconfig` and `.gitignore` but could
not satisfy its third bullet without breaking both image builds. Filed so the
residual work survives #15 being closed by PR #35.
## Problem
The org model `.dockerignore` starts with `.git`; this repo's does not, so every
`docker build` ships the full git history into the build context.
It cannot simply be added today. Both images read git metadata at build time, as
of `main` at `fbfe1df`:
1. **Backend.** `Dockerfile.backend:12` is `COPY .git /repo/.git`, present so
that `backend/Makefile`'s `VERSION := $(shell git describe --always --dirty)`
resolves. With `.git` in `.dockerignore` the `COPY` has no source and the
build fails outright.
2. **Frontend.** `Dockerfile` does `COPY . .` then `RUN make check`, whose test
step is the production `vite build`. `vite.config.js` lines 5-6 run
`execSync("git rev-parse --short HEAD")` and `execSync("git rev-parse HEAD")`
at config-eval time, so Vite throws before transforming any module. The
frontend does not `COPY .git` explicitly — it gets `.git` incidentally via
`COPY . .`, which is exactly why adding the ignore entry breaks it.
#17 covers the backend half: its definition of done already requires removing
`COPY .git /repo/.git` and driving the version from `ARG VERSION` instead. It
does **not** cover the frontend `vite.config.js` coupling, and neither issue owns
the `.dockerignore` line itself. That gap is what this issue is for.
## Definition of done
- [ ] `vite.config.js` no longer shells out to `git` at config-eval time in a
Docker build. Take the commit hash from an env var or build arg with a
fallback (so a missing `.git` degrades to a placeholder instead of throwing),
and pass it through from `Dockerfile`.
- [ ] `Dockerfile.backend` no longer needs `.git` — either land #17 first, or
confirm it has landed, rather than duplicating that change here.
- [ ] `.dockerignore` has `.git` as an entry.
- [ ] `docker build .` succeeds and the built page still shows a commit hash
(not a crash, not an empty string where a hash is expected).
- [ ] `docker build -f Dockerfile.backend .` succeeds and the binary still
reports a sensible version.
- [ ] Root `make check` and `cd backend && make check` both pass.
- [ ] `TODO.md` updated in the same commit.
- [ ] Commit title ends with ` (closes #N)`.
## Implementation requirements
- Sequence after #17, or coordinate with it — do not re-do the backend Dockerfile
rework in this issue.
- Leave the `.claude` entry in `.dockerignore` alone; that is #28's scope.
- `make` targets and `script/` entrypoints only for verification.
- No attribution trailers in the commit message.
Manager note — keeping this issue, attached to 1.0.0
Endorsing the split. Keep #36; do notreopen#15 and close this as a duplicate. Two reasons:
The vite.config.js coupling is a genuine new finding, not a restatement of #15. When I wrote #15 I named only the Dockerfile.backendCOPY .git blocker and pointed at #17 to resolve it. I missed that the frontend picks up .git incidentally through COPY . ., and that vite.config.js calls execSync("git rev-parse ...") at config-eval time — so Vite throws before transforming a single module. That half was owned by nobody: #15 didn't cover it, and #17's definition of done is scoped entirely to Dockerfile.backend and backend/Makefile. Verified that against #17's text; the claim is correct.
The scope here is materially different from #15's.#15 was three unrelated dotfile fixes. This is a build-system change touching vite.config.js, Dockerfile, and .dockerignore, sequenced behind #17. Reopening #15 to carry it would leave an issue whose title and first two-thirds are already done — exactly the kind of stale, half-satisfied issue that makes a tracker untrustworthy.
Attached to the 1.0.0 milestone, matching #15 and #17. The org-model .dockerignore compliance is a tag blocker and this is now the issue that owns it.
Sequencing
#17 first, then this.#17 removes COPY .git /repo/.git and moves the backend to ARG VERSION. Once that lands, this issue is only the frontend half plus the one-line .dockerignore entry — small and low-risk. Attempting them in the other order means re-doing #17's work here, which the implementation requirements already forbid.
One addition to the definition of done
The existing DoD says the built page must "still show a commit hash (not a crash, not an empty string where a hash is expected)". Tighten that: verify the hash rendered in the built page matches the actual commit being built, not merely that some non-empty string appears. A fallback placeholder that silently wins over the real value would satisfy a non-empty check while quietly breaking the footer's commit link (src/main.js:672) for every future build — a regression that would be easy to miss and annoying to trace later.
## Manager note — keeping this issue, attached to `1.0.0`
Endorsing the split. Keep #36; do **not** reopen #15 and close this as a duplicate. Two reasons:
1. **The `vite.config.js` coupling is a genuine new finding, not a restatement of #15.** When I wrote #15 I named only the `Dockerfile.backend` `COPY .git` blocker and pointed at #17 to resolve it. I missed that the frontend picks up `.git` incidentally through `COPY . .`, and that `vite.config.js` calls `execSync("git rev-parse ...")` at config-eval time — so Vite throws before transforming a single module. That half was owned by nobody: #15 didn't cover it, and #17's definition of done is scoped entirely to `Dockerfile.backend` and `backend/Makefile`. Verified that against #17's text; the claim is correct.
2. **The scope here is materially different from #15's.** #15 was three unrelated dotfile fixes. This is a build-system change touching `vite.config.js`, `Dockerfile`, and `.dockerignore`, sequenced behind #17. Reopening #15 to carry it would leave an issue whose title and first two-thirds are already done — exactly the kind of stale, half-satisfied issue that makes a tracker untrustworthy.
Attached to the `1.0.0` milestone, matching #15 and #17. The org-model `.dockerignore` compliance is a tag blocker and this is now the issue that owns it.
### Sequencing
**#17 first, then this.** #17 removes `COPY .git /repo/.git` and moves the backend to `ARG VERSION`. Once that lands, this issue is only the frontend half plus the one-line `.dockerignore` entry — small and low-risk. Attempting them in the other order means re-doing #17's work here, which the implementation requirements already forbid.
### One addition to the definition of done
The existing DoD says the built page must "still show a commit hash (not a crash, not an empty string where a hash is expected)". Tighten that: verify the hash rendered in the built page **matches the actual commit being built**, not merely that some non-empty string appears. A fallback placeholder that silently wins over the real value would satisfy a non-empty check while quietly breaking the footer's commit link (`src/main.js:672`) for every future build — a regression that would be easy to miss and annoying to trace later.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Split out of #15, which fixed the root
.editorconfigand.gitignorebut couldnot satisfy its third bullet without breaking both image builds. Filed so the
residual work survives #15 being closed by PR #35.
Problem
The org model
.dockerignorestarts with.git; this repo's does not, so everydocker buildships the full git history into the build context.It cannot simply be added today. Both images read git metadata at build time, as
of
mainatfbfe1df:Backend.
Dockerfile.backend:12isCOPY .git /repo/.git, present sothat
backend/Makefile'sVERSION := $(shell git describe --always --dirty)resolves. With
.gitin.dockerignoretheCOPYhas no source and thebuild fails outright.
Frontend.
DockerfiledoesCOPY . .thenRUN make check, whose teststep is the production
vite build.vite.config.jslines 5-6 runexecSync("git rev-parse --short HEAD")andexecSync("git rev-parse HEAD")at config-eval time, so Vite throws before transforming any module. The
frontend does not
COPY .gitexplicitly — it gets.gitincidentally viaCOPY . ., which is exactly why adding the ignore entry breaks it.#17 covers the backend half: its definition of done already requires removing
COPY .git /repo/.gitand driving the version fromARG VERSIONinstead. Itdoes not cover the frontend
vite.config.jscoupling, and neither issue ownsthe
.dockerignoreline itself. That gap is what this issue is for.Definition of done
vite.config.jsno longer shells out togitat config-eval time in aDocker build. Take the commit hash from an env var or build arg with a
fallback (so a missing
.gitdegrades to a placeholder instead of throwing),and pass it through from
Dockerfile.Dockerfile.backendno longer needs.git— either land #17 first, orconfirm it has landed, rather than duplicating that change here.
.dockerignorehas.gitas an entry.docker build .succeeds and the built page still shows a commit hash(not a crash, not an empty string where a hash is expected).
docker build -f Dockerfile.backend .succeeds and the binary stillreports a sensible version.
make checkandcd backend && make checkboth pass.TODO.mdupdated in the same commit.(closes #N).Implementation requirements
rework in this issue.
.claudeentry in.dockerignorealone; that is #28's scope.maketargets andscript/entrypoints only for verification.Manager note — keeping this issue, attached to
1.0.0Endorsing the split. Keep #36; do not reopen #15 and close this as a duplicate. Two reasons:
The
vite.config.jscoupling is a genuine new finding, not a restatement of #15. When I wrote #15 I named only theDockerfile.backendCOPY .gitblocker and pointed at #17 to resolve it. I missed that the frontend picks up.gitincidentally throughCOPY . ., and thatvite.config.jscallsexecSync("git rev-parse ...")at config-eval time — so Vite throws before transforming a single module. That half was owned by nobody: #15 didn't cover it, and #17's definition of done is scoped entirely toDockerfile.backendandbackend/Makefile. Verified that against #17's text; the claim is correct.The scope here is materially different from #15's. #15 was three unrelated dotfile fixes. This is a build-system change touching
vite.config.js,Dockerfile, and.dockerignore, sequenced behind #17. Reopening #15 to carry it would leave an issue whose title and first two-thirds are already done — exactly the kind of stale, half-satisfied issue that makes a tracker untrustworthy.Attached to the
1.0.0milestone, matching #15 and #17. The org-model.dockerignorecompliance is a tag blocker and this is now the issue that owns it.Sequencing
#17 first, then this. #17 removes
COPY .git /repo/.gitand moves the backend toARG VERSION. Once that lands, this issue is only the frontend half plus the one-line.dockerignoreentry — small and low-risk. Attempting them in the other order means re-doing #17's work here, which the implementation requirements already forbid.One addition to the definition of done
The existing DoD says the built page must "still show a commit hash (not a crash, not an empty string where a hash is expected)". Tighten that: verify the hash rendered in the built page matches the actual commit being built, not merely that some non-empty string appears. A fallback placeholder that silently wins over the real value would satisfy a non-empty check while quietly breaking the footer's commit link (
src/main.js:672) for every future build — a regression that would be easy to miss and annoying to trace later.