feat(singleton#1): foundation — postmaster + admin.json writer (Tier A pm2)#75
Conversation
….4 dream-readiness
Reconciliation with two-tier supervisor model:
- Group 1 (postmaster + dual-transport): scoped to Tier A pm2 only.
Tier B systemd-user / launchd ships separately via cutover G11.6.
Added admin.json writer module; refuses to claim "pm2" if already on Tier B.
Added --no-pm2 flag for Tier B-bound hosts.
Tightened acceptance criteria (admin.json supervisor field, pm2 jlist check,
refuse-when-already-Tier-B, --no-pm2 path).
- Group 6 (self-healing update): made supervisor-aware. Restart-primitive
dispatcher reads admin.json.supervisor and calls matching restart command:
pm2 → pm2 restart autopg-server
systemd-user → systemctl --user restart autopg.service
launchd → launchctl kickstart -k gui/$UID/dev.automagik.autopg
external → no-op + advisory log
Added Tier B + external integration tests.
Wave 2 dependency graph fix:
- Wave description said G4→G3→G7 but depends-on lines all pointed at G1.
- Corrected: G3.depends-on=G4 (provision needs cosign schema), G7.depends-on=G3
(roles/grants build on provision skeleton).
Doctor passive-reporting contract baked into G3 acceptance criteria:
- doctor reads admin.json.supervisor and runs matching liveness check.
- Never suggests swapping tiers (Felipe directive 2026-05-08).
- Cat 1 mutation: if admin.json says pm2 but entry missing, --fix re-registers.
Risk register expanded:
- Tier A + Tier B double-supervision (HIGH) — mitigated by hard MIGRATE
contract in cutover G11.6 + Group 1 refuse-when-Tier-B check.
- admin.json corruption (LOW) — doctor --fix Cat 1 rewrites from observed state.
- Tier B operator runs pgserve update (MEDIUM) — G6 supervisor-aware dispatch.
Cross-wish dependencies expanded:
- paired-with autopg-distribution-cutover (cohort sibling, owns G11.6 contract).
- paired-with canonical-pgserve-pm2-supervision (cohort sibling, Tier A only).
- blocks autopg-service-install-system (parked next-version wish).
Success criteria additions:
- doctor reports active supervisor by reading admin.json (passive).
- MIGRATE contract honor across pm2 → systemd-user transition is verifiable.
genie wish lint: clean (no violations).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
MEDIUM — terminology + file-path pin:
- 5 occurrences of "G11.6" → "G20" (cutover wish renumbered group during /wish pass).
- Group 1 deliverable 6 admin.json writer: pinned the file path to
`src/lib/admin-json.js`, declared co-ownership with cohort sibling
canonical-pgserve-pm2-supervision Group 1 deliverable 2, and made the
schema/enum explicit (supervisor ∈ {pm2, systemd-user, launchd, external}).
genie wish lint: clean (no violations).
Per /review verdict 2026-05-08 — non-blocking MEDIUM gaps closed.
W1 verdict was already SHIP*; these fixes were optional pre-flight tightening.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
…son writer (cohort foundation)
Lays the data-plane foundation for pgserve 2.4. Group 1 of the
`pgserve-singleton-no-proxy` wish (cohort dream of the v2.4 trio).
What ships:
- bin/postgres-server.js — new `postmaster` subcommand. Spawns
PostgresManager directly with `-k <socket-dir>` and `-p 5432`. No
router, no bun proxy, no daemon control socket. This is the entry
point pm2 (Tier A) — and later systemd-user / launchd (Tier B,
separate wish) — invokes for the `autopg-server` process.
- src/lib/socket-dir.js — `resolveSocketDir()` returns
`$XDG_RUNTIME_DIR/pgserve` (preferred, freedesktop convention) or
`/tmp/pgserve` (fallback for CI / minimal containers without XDG).
`ensureSocketDir()` creates with mode 0700 and probes writability so
failure surfaces here, not as a libpq bind error mid-pm2-backoff.
- src/lib/admin-json.js — cohort-shared atomic reader / merge-writer /
`assertSupervisor()` for `~/.autopg/admin.json`. Schema:
`{ supervisor, socketDir, port, installedAt }` with supervisor ∈
`{ "pm2" | "systemd-user" | "launchd" | "external" }`. Refuses to
downgrade Tier B → Tier A (operator must `autopg service uninstall`
first). Merge-aware: preserves the scrypt Basic-Auth scheme written
by the autopg console UI.
- src/postgres.js — PostgresManager honors an explicit `socketDir`
option. When set, the install path owns directory lifecycle: stop()
no longer rm's an operator-supplied dir.
- src/cli-install.cjs — DEFAULT_PORT 8432 → 5432; PM2_PROCESS_NAME
`pgserve` → `autopg-server`; new `--no-pm2` flag for CI fixture
provisioning and Tier B-bound hosts; pre-install
`assertSupervisor('pm2'|'external')` refuses to claim hosts already
owned by Tier B; canonical socket dir created + admin.json
supervisor record written atomically post-install. The existing
scrypt admin-password writer becomes merge-safe so both schemas
coexist on the same file.
Tests:
- tests/lib/admin-json.test.js — 18 tests covering write/read, atomic
semantics, merge with existing fields, Tier B downgrade refusal,
enum validation, assertSupervisor matrix.
- tests/cli-install.test.js — updated for the v2.4 surface
(autopg-server pm2 name, port 5432, postmaster subcommand args) +
6 new singleton tests: socket dir creation w/ mode 0700,
--socket-dir threading through pm2 args, admin.json fields,
--no-pm2 path, systemd-user lock refusal, /tmp fallback.
Acceptance (per wish Group 1):
- ✅ pgserve install creates `$XDG_RUNTIME_DIR/pgserve/` with mode
0700.
- ✅ pgserve port outputs 5432.
- ✅ pm2 entry name is `autopg-server` (renamed from `pgserve`).
- ✅ admin.json records supervisor: "pm2" + canonical socketDir.
- ✅ pgserve install refuses with non-zero when admin.json records
supervisor: "systemd-user".
- ✅ pgserve install --no-pm2 skips pm2 register but still writes
admin.json with supervisor: "external".
Validation (run in worktree):
- bun test tests/lib/admin-json.test.js → 18 pass / 0 fail.
- bun test tests/cli-install.test.js → 26 pass / 0 fail.
- bun run lint → clean.
- bun test (full) → 328 pass / 2 fail; the 2 pre-existing failures
are console/dist/ asset tests unaffected by this change.
`bun run typecheck` is referenced by the wish but does not exist as a
package script; the project relies on lint + tests for static gates.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
Warning Rate limit exceeded
You’ve run out of usage credits. Purchase more in the billing tab. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (8)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Code Review
This pull request implements the first phase of the pgserve singleton architecture, transitioning the data plane to a direct postmaster supervision model. Key changes include the introduction of a "postmaster" subcommand in bin/postgres-server.js for direct PostgreSQL management, the migration of the default port to 5432, and the renaming of the PM2 process to "autopg-server". A new coordination mechanism using ~/.autopg/admin.json is established to track active supervisors and prevent conflicting installations between PM2 and system-level services. Additionally, the PR introduces dedicated modules for atomic configuration management and canonical socket directory resolution. I have no feedback to provide.
There was a problem hiding this comment.
💡 Codex Review
https://github.com/namastexlabs/pgserve/blob/36ff93114b1addd043b3d551c3fab2e406c79b2a/src/cli-install.cjs#L644
Detect legacy pm2 process before starting new install
When upgrading a host that already has the pre-v2.4 pm2 entry (pgserve), this idempotency check only looks for autopg-server, so pgserve install treats the host as fresh and attempts a second pm2 start. On real upgrades this can fail with port/data-dir lock conflicts or leave the CLI reporting the wrong runtime state. The commit even defines LEGACY_PM2_PROCESS_NAME but never uses it, so the migration path is effectively broken until Group 6 lands.
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Implements Group 1 of
pgserve-singleton-no-proxywish. Cohort foundation for v2.4.What ships
bin/postgres-server.js(new): postmaster wrapper with-k <socketDir> -p 5432, dual-transport binding (UDS + TCP loopback).src/lib/socket-dir.js(new):resolveSocketDir()—$XDG_RUNTIME_DIR/pgserve(preferred) or/tmp/pgserve(CI fallback).src/lib/admin-json.js(new): cohort-shared atomic writer + reader +assertSupervisor()helper. Schema:{ supervisor, socketDir, port, installedAt }withsupervisor ∈ { "pm2" | "systemd-user" | "launchd" | "external" }. Atomic via<file>.tmp+fs.rename. Co-owned with cohort siblingcanonical-pgserve-pm2-supervisionGroup 1.src/cli-install.cjs(refactored): Tier A pm2 register (autopg-server);--no-pm2flag for CI / Tier B-bound hosts; refuses ifadmin.json.supervisor ∈ {systemd-user, launchd}.src/postgres.js(modified): postmaster spawn with new socket-dir wiring.tests/lib/admin-json.test.js; cli-install tests updated.Acceptance criteria (per wish G1)
pgserve installon fresh host creates$XDG_RUNTIME_DIR/pgserve/mode 0700.psql -h $XDG_RUNTIME_DIR/pgserve(no-p) connects post-install.psql -h 127.0.0.1 -p 5432connects post-install.pgserve portoutputs5432.pm2 jlist | jq '.[] | select(.name=="autopg-server")'non-empty post-install.~/.autopg/admin.jsonrecordssupervisor: "pm2"with the resolved socketDir.pgserve installrefuses when admin.json recordssystemd-user(Tier B host); locked remediation hint matches cohort.pgserve install --no-pm2skips pm2 register, writessupervisor: "external".Cohort dream context
Layer 1 (foundation) of v2.4 cohort dream batch (DREAM.md tracked under PR #74, PG task #6 / #7).
Unblocks Layer 2:
src/cli-install.cjsrefactor; library extraction follow-up in canonical wish)And Layer 3:
Test plan
bun test tests/lib/admin-json.test.js— 18 pass / 0 fail (98.18% lines covered)bun testfull suite (will run on push)bun run lint && bun run typecheck