live: heartbeat sync 2026-10-20T15:15:41-07:00 (Refs #11)
This commit is contained in:
@@ -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
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
## Handoff Location
|
||||
- put it at ~/Projects
|
||||
@@ -1,4 +1,10 @@
|
||||
{
|
||||
"v": 1,
|
||||
"lastConsolidatedAt": 1792530736757
|
||||
"lastConsolidatedAt": 1792534456791,
|
||||
"lastResult": {
|
||||
"at": 1792532921161,
|
||||
"sessions": 1,
|
||||
"deltas": 1,
|
||||
"model": "frank-zealot"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"v": 1,
|
||||
"lastConsolidatedAt": 1792534385325
|
||||
}
|
||||
@@ -275,13 +275,13 @@ transition = [ "fade" ]
|
||||
interval_seconds = 1200
|
||||
|
||||
[wallpaper.default]
|
||||
path = "/home/blank/.local/share/noctalia/wallpapers/wallhaven_1kdgpg.jpg"
|
||||
path = "/home/blank/.local/share/noctalia/wallpapers/wallhaven_nzz3gy.jpg"
|
||||
|
||||
[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]
|
||||
path = "/home/blank/.local/share/noctalia/wallpapers/wallhaven_1kdgpg.jpg"
|
||||
path = "/home/blank/.local/share/noctalia/wallpapers/wallhaven_nzz3gy.jpg"
|
||||
|
||||
[wallpaper.monitors.DP-2]
|
||||
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"
|
||||
|
||||
[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]
|
||||
unit = "imperial"
|
||||
|
||||
Reference in New Issue
Block a user