Landing blocker for #61 and #63: the deployment checkout is 12 commits behind and `merge --ff-only` refuses while tracked paths are dirty. Discard is not available here (workspace policy: no `checkout`/`stash` on shared state), so the dirt is committed. - `agent/APPEND_SYSTEM.md`: the point-of-use / one-work-log / PR-link doctrine, already byte-identical to `origin/main` (`cmp` against the trunk blob: no difference). No new prose — the commit exists so the trunk merge can proceed. - `agent/config.yml` and `agent/managed-skills/**`: the machine-live tier the heartbeat owns (AGENTS.md § Live-sync tiers). `ALLOW_SECRETS=1` was used, deliberately and after auditing the staged diff by hand: the only credential-shaped strings in it are two copies of `AKIA0000000000000EXAMPLE` — the inert all-zero AWS example id — and they appear inside the two skill pages that teach that exact placeholder shape. This checkout is still running the pre-#61 hook; the merged gate (value-scoped placeholder filter, `71601f7`) exempts this value, so the refusal dies with this landing. No `--no-verify` was used: the gate ran and its verdict is recorded here. Refs #61
2.1 KiB
2.1 KiB
name, description
| name | description |
|---|---|
| e2e-port-squat-triage | When an e2e seam on a fixed port fails weirdly (404s on routes that exist, stale behavior, health probe passes but app seems ancient), audit for leftover dev/debug servers squatting the port before believing any red or green. |
E2E fixed-port squat triage
Symptom classes (all seen with a stale server squatting the seam's fixed port)
- Routes that exist in current
dist/source return 404 ("Cannot POST /api/...") while unit tests through the same app factory pass. - A seam that is green but exercises old code: its setup curls
http://host:PORT/healthand gets a response from whoever owns the port — a leftover server, not the one it just spawned (the spawned one dies or idles with EADDRINUSE, sometimes still showing inpgrep). - Behavior matches an older build (missing mounts/guards) despite a fresh build step.
Triage recipe (before touching code)
- Who owns the port:
ss -tlnp 2>/dev/null | grep :PORT - List every server process with start times:
for p in $(pgrep -f "path/to/server-entry"); do ps -o pid,lstart,cmd -p $p --no-headers; done - Compare start times against the build artifact timestamps (
ls -la dist/...). A server older than the dist you just built is a liar — its in-memory modules predate the code under test. - Kill all leftovers, then re-check:
pgrep -f "server-entry" || echo all-dead. - Rerun the seam. Only now is red/red and green/green meaningful.
Why it happens
kill %1in non-interactive bash fails silently (no job control) — use explicit PIDs orpkill -f <pattern>.- Seam setups that "wait for health" cannot distinguish their own server from a squatter on the same port; a pre-flight "port must be free" assertion is the permanent fix (assert before spawn).
Hardening (if you own the seam)
Add to setup, before spawning: fail fast if the port is already listening — turns the silent liar into a loud error:
ss -tln "sport = :PORT" | grep -q LISTEN && { echo "port PORT busy — kill leftovers first" >&2; return 1; }