live: heartbeat sync 2026-10-20T15:15:41-07:00 (Refs #11)
This commit is contained in:
1 parent
495e2229f5
commit
6af3714bd0
10 files changed
+193
-5
No files matched your search
@@ -0,0 +1,55 @@
|
|||||||
|
---
|
||||||
|
name: franksign-worktree-db-cred-trap
|
||||||
|
description: "Diagnose franksign e2e seam 5 / health 503 db:down in a fresh worktree: setup-dev.sh minted a password that mismatches the shared franksign-db container."
|
||||||
|
---
|
||||||
|
|
||||||
|
# franksign fresh-worktree DB credential trap
|
||||||
|
|
||||||
|
## Symptom
|
||||||
|
`tests/run.sh` in a fresh franksign worktree fails seam 5 ("e2e server did not
|
||||||
|
become healthy") while the server log says `franksign-api listening on :3100`.
|
||||||
|
Manual probe shows the server IS up:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
PORT=3100 node --env-file=.env apps/api/dist/cli.js >/tmp/manual-e2e.log 2>&1 &
|
||||||
|
sleep 2; curl -s http://127.0.0.1:3100/health
|
||||||
|
# -> 503 {"status":"degraded","db":"down",...}
|
||||||
|
```
|
||||||
|
|
||||||
|
Not a regression, not a :3100 port collision (check `ss -tlnp | grep 3100` to rule that out).
|
||||||
|
|
||||||
|
## Root cause
|
||||||
|
`infra/setup-dev.sh` mints a fresh `POSTGRES_PASSWORD` per checkout
|
||||||
|
(`if [ ! -f infra/postgres.env ]`), but `franksign-db` + `franksign-pgdata`
|
||||||
|
are shared box state owned by the main checkout
|
||||||
|
(`~/Projects/franksign`). The new worktree's `.env` DATABASE_URL then fails
|
||||||
|
TCP auth against the initialized volume.
|
||||||
|
|
||||||
|
The setup script masks it: its readiness gate is
|
||||||
|
`podman exec franksign-db pg_isready`, which uses the in-container local
|
||||||
|
socket and passes regardless of password — so setup prints "postgres ready"
|
||||||
|
while the checkout is dead on arrival.
|
||||||
|
|
||||||
|
## Fix (git-ignored files, no commit needed)
|
||||||
|
Copy the shared credentials from the owning checkout:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
grep DATABASE_URL /home/blank/Projects/franksign/.env # source of truth
|
||||||
|
# PUT that exact DATABASE_URL line into this worktree's .env
|
||||||
|
# PUT the matching POSTGRES_PASSWORD into this worktree's infra/postgres.env
|
||||||
|
```
|
||||||
|
|
||||||
|
Gotcha: the shared password may contain literal `$$`. Keep it byte-for-byte —
|
||||||
|
systemd `EnvironmentFile` and `node --env-file` both read values literally,
|
||||||
|
so `$$` in the file IS `$$` in the password. No escaping, no de-escaping.
|
||||||
|
|
||||||
|
## Verify
|
||||||
|
```bash
|
||||||
|
PORT=3100 node --env-file=.env apps/api/dist/cli.js & # then
|
||||||
|
curl -fsS http://127.0.0.1:3100/health # -> {"status":"ok","db":"up"}
|
||||||
|
tests/run.sh # 14/14
|
||||||
|
```
|
||||||
|
|
||||||
|
## Permanent fix (proposed, not yet landed)
|
||||||
|
`setup-dev.sh` should reuse `~/.config/containers/systemd/postgres.env`
|
||||||
|
(symlink to the owning checkout) when present instead of minting new creds.
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
---
|
||||||
|
name: land-branch-without-checkout
|
||||||
|
description: "Open a PR from a shared worktree when workspace policy blocks git checkout/restore: push a named branch ref from HEAD without switching branches."
|
||||||
|
---
|
||||||
|
|
||||||
|
# Landing a branch when `git checkout` is policy-blocked
|
||||||
|
|
||||||
|
Shared-workspace policy blocks `git checkout` and `git restore` (working-tree
|
||||||
|
switches could strand concurrent agents' uncommitted work). You still must ship
|
||||||
|
the commit on the current worktree branch as a named `chore|feat|fix/<issue>-<slug>`
|
||||||
|
branch. Never work around the block — go around it via refs.
|
||||||
|
|
||||||
|
## Sequence
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 1. commit only your files (atomic); leave other dirty paths alone
|
||||||
|
git add <your-files> && git commit -m "..."
|
||||||
|
|
||||||
|
# 2. branch ref at HEAD — no working-tree change, stays on wt/<...>
|
||||||
|
git branch <type>/<issue>-<slug> HEAD
|
||||||
|
git push origin <type>/<issue>-<slug> # pre-push hooks still run
|
||||||
|
|
||||||
|
# 3. PR via tracker API with head = pushed ref (see gitea-pr-api-cycle / gh)
|
||||||
|
```
|
||||||
|
|
||||||
|
- The worktree stays checked out on `wt/<timestamp>`; the new branch exists
|
||||||
|
only as the pushed ref (plus a local ref that merges cleanly later).
|
||||||
|
- `-u` upstream tracking on the wt branch is misleading — skip it; set
|
||||||
|
`git config branch.<name>.remote origin` + `.merge` only if you will
|
||||||
|
later check the branch out.
|
||||||
|
- Dirty regenerated fixtures left behind (e.g. `gen:sample` PDFs rewritten
|
||||||
|
by setup/gate runs): `git restore` is also blocked — do NOT edit-forward
|
||||||
|
to revert them; report them. They are regenerated on every bootstrap, so
|
||||||
|
dirt is expected and harmless.
|
||||||
|
|
||||||
|
## Verify
|
||||||
|
|
||||||
|
- `git ls-remote --heads origin <branch>` prints the same sha as `git rev-parse HEAD`.
|
||||||
|
- PR API returns 201 with `head.sha` equal to that sha.
|
||||||
|
|
||||||
|
## Do NOT
|
||||||
|
|
||||||
|
- `git checkout -b`, `git stash`, `git restore`, `git reset --hard` here —
|
||||||
|
all working-tree mutations the policy can block, and stashes in a shared
|
||||||
|
checkout are a cross-agent footgun.
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
---
|
||||||
|
name: typescript-fleet-repo-bootstrap
|
||||||
|
description: "Initialize a TypeScript monorepo (Bun workspaces + Turborepo + Biome + Express/Vite + quadlet dev DB + Storybook/Playwright gates) on Frank's fleet, with the traps that cost hours at franksign init."
|
||||||
|
---
|
||||||
|
|
||||||
|
# TypeScript fleet repo bootstrap
|
||||||
|
|
||||||
|
Bootstrap a fleet-style TS monorepo the way franksign was initialized (2026-10-20):
|
||||||
|
Bun workspaces + Turborepo + Biome + Express 5 on Node + Vite/React SPA + quadlet
|
||||||
|
dev Postgres + Storybook-as-component-test + prod-shaped Playwright e2e, gated by a
|
||||||
|
single `tests/run.sh` seam runner (serverAppConfigs pattern).
|
||||||
|
|
||||||
|
## Shape
|
||||||
|
|
||||||
|
```
|
||||||
|
apps/ homepage (zero-JS), web (Vite+React SPA), api (Express, single origin: /, /app, /api, /health)
|
||||||
|
packages/ domain libs (each: src/*.ts, tests colocated, tsc -p tsconfig.build.json)
|
||||||
|
templates/ data the API serves
|
||||||
|
tests/ run.sh + seams/*.bats + e2e/*.spec.ts + lib/ guards (.mjs)
|
||||||
|
infra/ quadlet/*.container + setup-dev.sh (idempotent bootstrap)
|
||||||
|
<repo>-docs/ OKF v0.2 KB: index.md, log.md, read-only/ (agent-off-limits)
|
||||||
|
AGENTS.md git law (trunk-based, --no-ff, explicit merge OK) + TDD tiers + docs law
|
||||||
|
HANDOFF.md at repo base for worktree-based future sessions
|
||||||
|
```
|
||||||
|
|
||||||
|
## Non-obvious traps (all measured on Frank's box, Node 26 / bun 1.4.3 / playwright 1.64)
|
||||||
|
|
||||||
|
- **Playwright `testDir` resolves against process CWD, not the config file.**
|
||||||
|
Pin the seam to invoke playwright with `cd` into the spec dir.
|
||||||
|
- **A `testMatch` regex with a leading `^` silently matches nothing** — Playwright
|
||||||
|
tests it against prefixed paths; "No tests found", zero diagnostics. Anchor only
|
||||||
|
the trailing `$`. And keep raw `/` out of the pattern if a guard script parses
|
||||||
|
the config literals.
|
||||||
|
- **`tsc` with `noEmit: false` but no `rootDir`/`outDir` emits `.js` strays into
|
||||||
|
`src/`** while package `main` points at `dist/` — the strays resurface on every
|
||||||
|
build. Pin `rootDir: "src", outDir: "dist", declaration: true` in every
|
||||||
|
tsconfig.build.json.
|
||||||
|
- **`bunx <tool>` ignores the workspace install** and pulls its own version (observed
|
||||||
|
with biome and playwright). Git hooks MUST call `./node_modules/.bin/<tool>`.
|
||||||
|
- **Node 26 rejects `--env-file-if-set`** (no "if-set" variant on that build);
|
||||||
|
use `--env-file=<file>` — a shell-set env var still wins over file values, so
|
||||||
|
`PORT=3100 node --env-file=.env dist/cli.js` overrides cleanly.
|
||||||
|
- **Quadlet resolves `EnvironmentFile=` relative to the UNIT directory**, not the
|
||||||
|
repo: `setup-dev.sh` must link the env file beside the unit in
|
||||||
|
`~/.config/containers/systemd/`. Generated quadlet units cannot be
|
||||||
|
`systemctl --user enable --now`'d — the generator's `default.target.wants`
|
||||||
|
symlink IS the enablement; plain `start` is enough.
|
||||||
|
- **`gitignore` rule `.env.*` swallows `.env.example`** — add the `!.env.example`
|
||||||
|
negation when you write the first ignore file.
|
||||||
|
- **Gitea 1.27.3 API create-repo with a JSON body can answer 422 `[Name]: Required`**
|
||||||
|
even when the field is present; probe `/api/v1/repos/<owner>/<name>` first — it
|
||||||
|
may already exist (empty = ready for `git push -u origin main`).
|
||||||
|
- **Biome 2.x**: `biome migrate` needs `--write` (without it, it only prints the
|
||||||
|
plan) and migrates `rules.recommended` → `rules.preset`; `check --write` skips
|
||||||
|
`useTemplate`/`noNonNullAssertion` (unsafe) — prefer rewriting `!` assertions to
|
||||||
|
named lookups so `--unsafe` never touches tests.
|
||||||
|
- **Grafana-grade gate law** (from serverAppConfigs): every e2e spec must be routed
|
||||||
|
by a `projects[].testMatch` or it silently never runs — ship a scaffold-guard
|
||||||
|
script that fails the seam on an orphan spec.
|
||||||
|
|
||||||
|
## Gate wiring
|
||||||
|
|
||||||
|
`tests/run.sh` (bats seams: build, unit, docs-lint, homepage budget, quadlet,
|
||||||
|
storybook build, e2e) ← pre-push hook; pre-commit = secret-regex scan on staged
|
||||||
|
diff + `./node_modules/.bin/biome check` on staged code. e2e seam boots the
|
||||||
|
prod-shaped stack (built assets + Express + quadlet DB on a dedicated port,
|
||||||
|
health-gated with `curl` before Playwright starts).
|
||||||
|
|
||||||
|
## Session close-out
|
||||||
|
|
||||||
|
log.md entry with `(cwd · session)` footer; HANDOFF.md updated; origin on Gitea
|
||||||
|
owner `dank`; PR bodies carry the attribution footer.
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"v": 1,
|
||||||
|
"lastConsolidatedAt": 1792532762570
|
||||||
|
}
|
||||||
Whitespace-only changes.
@@ -0,0 +1,2 @@
|
|||||||
|
## Handoff Location
|
||||||
|
- put it at ~/Projects
|
||||||
@@ -1,4 +1,10 @@
|
|||||||
{
|
{
|
||||||
"v": 1,
|
"v": 1,
|
||||||
"lastConsolidatedAt": 1792530736757
|
"lastConsolidatedAt": 1792534456791,
|
||||||
|
"lastResult": {
|
||||||
|
"at": 1792532921161,
|
||||||
|
"sessions": 1,
|
||||||
|
"deltas": 1,
|
||||||
|
"model": "frank-zealot"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Whitespace-only changes.
@@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"v": 1,
|
||||||
|
"lastConsolidatedAt": 1792534385325
|
||||||
|
}
|
||||||
@@ -275,13 +275,13 @@ transition = [ "fade" ]
|
|||||||
interval_seconds = 1200
|
interval_seconds = 1200
|
||||||
|
|
||||||
[wallpaper.default]
|
[wallpaper.default]
|
||||||
path = "/home/blank/.local/share/noctalia/wallpapers/wallhaven_1kdgpg.jpg"
|
path = "/home/blank/.local/share/noctalia/wallpapers/wallhaven_nzz3gy.jpg"
|
||||||
|
|
||||||
[wallpaper.last]
|
[wallpaper.last]
|
||||||
path = "/home/blank/.local/share/noctalia/wallpapers/wallhaven_1kdgpg.jpg"
|
path = "/home/blank/.local/share/noctalia/wallpapers/wallhaven_nzz3gy.jpg"
|
||||||
|
|
||||||
[wallpaper.monitors.DP-1]
|
[wallpaper.monitors.DP-1]
|
||||||
path = "/home/blank/.local/share/noctalia/wallpapers/wallhaven_1kdgpg.jpg"
|
path = "/home/blank/.local/share/noctalia/wallpapers/wallhaven_nzz3gy.jpg"
|
||||||
|
|
||||||
[wallpaper.monitors.DP-2]
|
[wallpaper.monitors.DP-2]
|
||||||
path = "/home/blank/.local/share/noctalia/wallpapers/wallhaven_oxex69.jpg"
|
path = "/home/blank/.local/share/noctalia/wallpapers/wallhaven_oxex69.jpg"
|
||||||
@@ -290,7 +290,7 @@ transition = [ "fade" ]
|
|||||||
path = "/home/blank/.local/share/noctalia/wallpapers/wallhaven_v9e2w3.jpg"
|
path = "/home/blank/.local/share/noctalia/wallpapers/wallhaven_v9e2w3.jpg"
|
||||||
|
|
||||||
[wallpaper.monitors.eDP-1]
|
[wallpaper.monitors.eDP-1]
|
||||||
path = "/home/blank/.local/share/noctalia/wallpapers/wallhaven_1kdgpg.jpg"
|
path = "/home/blank/.local/share/noctalia/wallpapers/wallhaven_nzz3gy.jpg"
|
||||||
|
|
||||||
[weather]
|
[weather]
|
||||||
unit = "imperial"
|
unit = "imperial"
|
||||||
|
|||||||
Reference in new issue
Block a user