Context
The repo carries two JavaScript lockfiles, package-lock.json and yarn.lock, but only one of them ships. The Docker build uses yarn exclusively:
- Dockerfile:28 — comment: "yarn matches yarn.lock, which jsbundling-rails selects over package-lock.json."
- Dockerfile:31 —
npm install -g yarn
- Dockerfile:38 —
COPY package.json yarn.lock ./
- Dockerfile:39 —
RUN yarn install --frozen-lockfile
package-lock.json is never copied into the image and never installed from. It is dead weight with two active costs:
- It doubles every Dependabot alert. The 6 open alerts on
main are 3 advisories (seroval, js-yaml, brace-expansion) counted once per lockfile. Halving the noise makes the next batch readable at a glance instead of requiring dedup by hand.
- The two files can silently disagree. They happen to match today — both resolve seroval 1.3.2, js-yaml 4.1.0, brace-expansion 1.1.11 (verified 2026-07-28) — but nothing enforces that. A contributor running
npm install updates only package-lock.json, which then describes a dependency tree that never deploys, while the tree that does deploy goes unreviewed.
Both lockfiles were last modified 2026-07-19 at the same timestamp, so no divergence has accumulated yet. This is the cheap moment to remove it.
Outcome: one lockfile, one source of truth for what ships; Dependabot alert count halves for every future batch.
Plan
Files touched:
package-lock.json (deleted)
.gitignore (add an entry so an accidental npm install cannot re-introduce it)
Steps:
- Confirm nothing references it: search the repo for
package-lock outside node_modules — expect hits only in Dockerfile:28 (the explanatory comment, which stays accurate and should remain) and any CI config.
- Confirm no GitHub Actions workflow consumes it. As of 2026-07-28 the repo has no
.github/workflows directory at all, so there is nothing to update; re-verify rather than assume.
git rm package-lock.json.
- Add
/package-lock.json to .gitignore with a one-line comment naming yarn.lock as the single source of truth, so npm install cannot silently restore it.
- Verify the yarn path still installs clean from scratch.
Acceptance Criteria
- Setup: repo at HEAD after the change → Action:
git ls-files package-lock.json → Expected: empty output (file is untracked and gone).
- Setup: clean
node_modules → Action: rm -rf node_modules && yarn install --frozen-lockfile → Expected: exits 0, proving the build path in Dockerfile:39 is unaffected by the deletion.
- Setup: repo at HEAD → Action:
yarn build && yarn test → Expected: bundle builds and JS tests pass, confirming nothing in the toolchain read the deleted file.
- Setup:
.gitignore updated → Action: run npm install then git status --porcelain → Expected: package-lock.json is regenerated on disk but does NOT appear as an untracked change, proving the ignore rule holds.
- Setup: merged to main → Action: re-read Dependabot open alerts → Expected: exactly 3 remain (one per advisory instead of two), all attributed to yarn.lock. The remaining 3 are cleared by the sibling solid-js bump ticket.
Tests + evals
- Deleting an unused file needs no new unit test; the acceptance criteria above are the runnable checks (
yarn install --frozen-lockfile, yarn build, yarn test, and the .gitignore round-trip).
- No LLM surface — no eval suite.
Docs pages touched
None required. Dockerfile:28 already explains why yarn.lock wins; leave that comment in place since it documents the decision this ticket completes.
Out of scope
- Switching the project off yarn, or changing the Docker build to npm/bun.
- Bumping any dependency version — the sibling ticket owns the solid-js, js-yaml, and brace-expansion upgrades and depends on this one landing first.
- Adding a CI check that enforces single-lockfile discipline.
- Touching
yarn.lock contents in any way.
Blocks #93
Context
The repo carries two JavaScript lockfiles,
package-lock.jsonandyarn.lock, but only one of them ships. The Docker build uses yarn exclusively:npm install -g yarnCOPY package.json yarn.lock ./RUN yarn install --frozen-lockfilepackage-lock.jsonis never copied into the image and never installed from. It is dead weight with two active costs:mainare 3 advisories (seroval, js-yaml, brace-expansion) counted once per lockfile. Halving the noise makes the next batch readable at a glance instead of requiring dedup by hand.npm installupdates only package-lock.json, which then describes a dependency tree that never deploys, while the tree that does deploy goes unreviewed.Both lockfiles were last modified 2026-07-19 at the same timestamp, so no divergence has accumulated yet. This is the cheap moment to remove it.
Outcome: one lockfile, one source of truth for what ships; Dependabot alert count halves for every future batch.
Plan
Files touched:
package-lock.json(deleted).gitignore(add an entry so an accidentalnpm installcannot re-introduce it)Steps:
package-lockoutside node_modules — expect hits only in Dockerfile:28 (the explanatory comment, which stays accurate and should remain) and any CI config..github/workflowsdirectory at all, so there is nothing to update; re-verify rather than assume.git rm package-lock.json./package-lock.jsonto.gitignorewith a one-line comment naming yarn.lock as the single source of truth, sonpm installcannot silently restore it.Acceptance Criteria
git ls-files package-lock.json→ Expected: empty output (file is untracked and gone).node_modules→ Action:rm -rf node_modules && yarn install --frozen-lockfile→ Expected: exits 0, proving the build path in Dockerfile:39 is unaffected by the deletion.yarn build && yarn test→ Expected: bundle builds and JS tests pass, confirming nothing in the toolchain read the deleted file..gitignoreupdated → Action: runnpm installthengit status --porcelain→ Expected: package-lock.json is regenerated on disk but does NOT appear as an untracked change, proving the ignore rule holds.Tests + evals
yarn install --frozen-lockfile,yarn build,yarn test, and the .gitignore round-trip).Docs pages touched
None required. Dockerfile:28 already explains why yarn.lock wins; leave that comment in place since it documents the decision this ticket completes.
Out of scope
yarn.lockcontents in any way.Blocks #93