Drafts CHANGELOG_PENDING.md entries from Conventional Commit subjects on
every push to main -- feat/fix/refactor/perf/security bucketed into
Added/Fixed/Changed, chore/ci/test/docs/style/merge skipped, anything
mentioning internal infra hostnames dropped. No LLM call, no network
access, purely regex over commit subjects already in the pushed range.
Never touches CHANGELOG.md -- still needs a human to fold an entry in.
Root cause traced: package-lock.json was missing per-platform optional
dependency entries for Rollup/esbuild's Linux native binaries
(npm/cli#4828) since it had only ever been regenerated on darwin-arm64.
npm ci on the Linux runner silently skipped them, Vite's synchronous
require() at vitest startup threw before any test loaded. Fixed as a
side effect of the full package-lock.json regeneration in a0ad052.
Confirmed via Gitea Actions run history: failure before, 2 consecutive
successes after.
The forks-pool change didn't fix it (failure went from 1s to 0s, if
anything worse) -- reverting to plain 'npm test' since it's no more or
less broken and is simpler. Documenting this as a known open item needing
someone with actual authenticated Gitea dashboard access, rather than
continuing to guess blindly from outside.
'npm test' (default vitest thread pool) fails in ~1s on this Gitea Actions
runner for no reason reproducible locally (plain run, CI=true, and a fully
fresh rm -rf node_modules && npm ci all pass 215/215). Forcing the forks
pool with a small fixed worker count (min 1, max 2) is a standard fix for
this class of CI-only vitest worker-pool crash.
Discovered live on Erik just now: 'npm run build' returns exit code 2
because of pre-existing src/mcp-server/index.ts type errors (unrelated to
the server.js/API-server deploy path -- already documented in the
2026-07-16 audit), but with noEmitOnError left at its default (false) it
still correctly emits dist/api/index.js, dist/api/server.js, etc. Both
build-verify.yml and deploy-from-git.sh were treating that non-zero exit
as a hard failure -- the CI run for the previous commit failed on exactly
this, and deploy-from-git.sh's would have aborted a real deploy
at the same step had I used it instead of manual commands. Now both check
for the specific required output files instead of trusting tsc's exit code.
Two consecutive PeerCortex deploys today (2026-07-16) broke in the same
way: server.js requires local files (src/backend/config.js,
src/backend/services/smtp.js) that were never actually uploaded to Erik,
because the deploy process was ad-hoc 'cat file | ssh' per-file uploads
with no systematic check that every require() target actually exists on
the target machine. A missing npm dependency (pg) caused the same class
of problem separately.
- .github/workflows/build-verify.yml: runs on every push/PR (Gitea Actions
already has a working runner for this repo, confirmed via the existing
.github/workflows/security-scan.yml on the github-import/main branch).
npm ci, syntax-checks server.js + the other top-level .js files, verifies
every local require() target resolves to an actual file, typechecks
(informational for now -- see the step comment for why), builds dist/,
runs the existing vitest suite. Catches both of today's failures before
they'd ever reach Erik.
- deploy-from-git.sh: replaces the per-file upload process with a single
git pull + npm ci + require()-check + syntax-check + build + backup +
pm2 restart sequence, run manually on Erik. Deliberately NOT wired to a
Gitea Action with SSH secrets -- Erik hosts many unrelated production
services and main can contain code that hasn't been live-verified yet,
so the actual deploy trigger stays a human decision. CI catches
what's broken; this makes running the fix a single repeatable command
instead of a manually-assembled file list.