---
name: setup-hetzner-ardent-dev
description: Set up, start, switch, verify, or repair Sellable's Hetzner Codex development environment backed by a writable Ardent copy of production and loopback Supabase services. Use when the user asks to provision or rebuild the remote dev lane, connect Codex Desktop over SSH, link or verify Ardent, serve Sellable in Next.js development or production-build mode, expose authenticated UAT through SSH/ngrok, diagnose copied-data/auth failures, or confirm production credential isolation.
---

# Set Up Hetzner Ardent Development

Operate the remote lane from committed, fail-closed scripts. Preserve
production-shaped Ardent data and isolate it through credentials and runtime
configuration rather than rewriting copied rows.

Read [references/runtime-contract.md](references/runtime-contract.md) before
the first mutation or mode switch.

## Source of Truth

Use the Sellable application repository's committed files:

- `infra/dev-lane/README.md`
- `docs/dev-lane/operator-runbook.md`
- `infra/dev-lane/sync-dev-lane-access.sh`
- `infra/dev-lane/ardent-remote-development.sh`
- `scripts/dev-lane/verify-ardent-remote-development.mjs`
- `scripts/dev-lane/verify-remote-production-credential-isolation.mjs`

Do not recreate these flows from chat history.

## Workflow

1. Inspect the current SSH host, Git state, tmux sessions, listeners, Ardent
   connector/branch status, and local Supabase status before changing anything.
2. Reuse a healthy connector and branch. Never delete, recreate, or retry a
   healthy connector merely to make setup look fresh.
3. From Christian's trusted laptop, synchronize access and product surfaces:

   ```bash
   infra/dev-lane/sync-dev-lane-access.sh \
     --ssh-alias dev-lane-coder-1
   ```

4. On Hetzner, inspect the Git-to-Ardent mapping, then start or reconcile the
   branch-backed runtime:

   ```bash
   cd /home/codex/workspace/dittto-fresh-1/web
   infra/dev-lane/ardent-branch-workspace.sh name
   npm run ardent:setup
   npm run ardent:status
   ```

5. Choose one serving mode:

   - Run `npm run dev:ardent` while editing for hot reload.
   - Run `npm run preview:ardent` for production-like UAT and faster steady
     page serving after a one-time build.
   - Use `npm run build:ardent` and `npm run start:ardent` when build and serve
     need separate tmux sessions.

6. Keep the app and local Supabase ports loopback-only. Prefer an SSH tunnel.
   Use the bundled guarded UAT gateway before ngrok; never expose the Next.js
   or Supabase ports directly.
7. Run both runtime and credential-isolation verifiers.
8. Report the exact branch, repo slot, serving mode, loopback port, public or
   tunneled URL, build/start timing, and verification results without printing
   credentials.

## Required Invariants

- Use Ardent's direct TLS branch URL, not a Supabase pooler URL.
- Derive one stable Ardent branch from each Git branch. Use an explicit branch
  override only to resume a known legacy branch.
- Keep every Ardent branch production-shaped and writable.
- Do not register a data-mutating `branch_sql` hook.
- Never copy a production database URL/password, production Supabase
  service-role key, or real outbound-provider credentials to Hetzner.
- Permit only Ardent branch credentials and host-local Supabase credentials.
- Disable background dispatchers and replace provider credentials with
  `disabled-local-only`.
- Generate `NEXTAUTH_SECRET` and `INTERNAL_SERVICE_SECRET` per host.
- Never merge the generated runtime env with the canonical production `.env`.
- Keep runtime env files Git-ignored and mode `0600`.
- Preserve dirty checkouts and unrelated repo slots.
- Never use Git worktrees; use the existing standalone clones.

## Verification

Require the remote verifier to prove:

- branch connectivity and writability;
- production-shaped workspace, campaign, sender, auth-user, and membership
  data;
- no legacy branch-mutation schema;
- local Supabase Auth and REST health;
- rendered app health;
- disabled provider credentials; and
- no installed production credentials or production write authority.

Then run the trusted-laptop credential comparison. Treat a public page render
without authenticated copied data as insufficient.

## Recovery Rules

- If the connector is still copying with no terminal error, keep the bounded
  waiter and do not mutate it.
- If Storage alone fails because copied `storage.migrations` names conflict,
  continue only when the requested UAT does not use Storage and Auth, REST,
  database queries, and the application pass.
- If authentication works once but fails after refresh, verify that the client
  reads the existing session before attempting refresh and that the browser
  Supabase URL points through the guarded gateway.
- If development compilation is the bottleneck, build in an unused standalone
  clone and switch the gateway only after `next start` is healthy.
- If `next build` reaches Node's default heap limit, keep the machine healthy
  and rerun with the documented 12 GB `NODE_OPTIONS` setting. A V8 4 GB
  out-of-memory error is not proof that the Hetzner host lacks RAM.
- If any verifier detects a production credential, stop the runtime and remove
  that remote credential before continuing.
