66 lines
11 KiB
Markdown
66 lines
11 KiB
Markdown
# ORCHESTRATOR.md — Operating Manual for Successor Agents
|
|
|
|
You are taking over the autonomous development loop on **SpaceWanderer** (browser game: dungeon-crawler-type, very replayable — turn-based space adventure where you build & expand your ship/base from found parts and resources, survive random encounters, manage a crew of flawed humans with good/bad traits; server-authoritative turn engine). Gameplay reference: Out There (Android), but more building-focused. **Single player only, by design** — no auth/accounts/multiplayer, ever, unless the user changes that decision. This document captures operational knowledge that is NOT written down in AGENTS.md. Read AGENTS.md first — it defines the mandatory change process and this file complements it.
|
|
|
|
Credentials are deliberately NOT stored in this file — see §1 for where they live. Never paste token values into any tracked file.
|
|
|
|
## 1. Project identity
|
|
- Repo: Gitea at https://git.kkhost.pl → org **OpenCode**, repo **SpaceWanderer** (full name `OpenCode/SpaceWanderer`). Every Gitea API/MCP call uses owner=`OpenCode`, repo=`SpaceWanderer`.
|
|
- Local workdir + prod deploy dir: `/home/krzyw/projects/sandbox/space-wanderer` (git checkout; `docker compose up -d --build` deploys from here).
|
|
- Prod URL (planned, not deployed yet): https://space-wanderer.dev.kkhost.pl (Traefik → docker-compose stack on this host); first deploy happens after the initial scaffold. Once live, `GET /api/version` reports the running version.
|
|
- Gitea API access for git.kkhost.pl: prefer the gitea MCP tools — they are already configured with a token. For raw REST/curl, read the current token from the local .env file at repo root (variable `GITEA_TOKEN`; .env is gitignored and must never be committed): `source .env && curl -s -H "Authorization: token $GITEA_TOKEN" https://git.kkhost.pl/api/v1/user`. (Incident note, Sept 2026: an early draft of the Flight-Ops doc committed a live token to the repo; that commit was purged from all refs and the token has since been rotated — never repeat this.)
|
|
- Current user: kamilkrzywda (id 1).
|
|
- **Current state:** initial scaffold (v0.1.0) is done on branch `scaffold-base` off master — base stack copied/adapted from `../flight`, scificn-ui frontend integrated, CI/e2e pipeline in place; not merged/deployed yet (first deploy happens after the scaffold lands). From here the loop below applies as-is.
|
|
|
|
## 2. The loop (per issue)
|
|
1. Small incremental change on a feature branch off `master`; connected issues may share one branch/PR with a single version bump.
|
|
2. Bump `package.json` version + add CHANGELOG.md entry at top: `## v<version> — YYYY-MM-DD HH:MM` then bullet points of what changed (docs-only changes get patch bumps too).
|
|
3. Local verification ONLY (there are NO local e2e runs): `npx tsc --noEmit`, `npx vitest run` (the whole unit suite must pass — the test count grows over time, so compare against the previous green run, never a hardcoded number), `npx playwright test --list` (all specs compile and list).
|
|
4. Push → CI (~7 min) → **auto-merge on green** (PRs have auto-merge configured; no manual merge needed — verify via `GET /pulls/{n}` that state=closed and merged_at is set). Note: if a PR was created via API rather than create-on-push, double-check auto-merge actually fires.
|
|
5. Tag the version on master: `git tag v<version> origin/master && git push origin v<version>` (after `git fetch origin master`).
|
|
6. Deploy prod in a PTY (long task): `cd /home/krzyw/projects/sandbox/space-wanderer && git checkout master && git reset --hard origin/master && docker compose up -d --build`; then verify `curl https://space-wanderer.dev.kkhost.pl/api/version` returns the new version and the root page is HTTP 200.
|
|
7. Close each issue with a comment: what changed, version, PR number, merge commit SHA, deployed URL.
|
|
8. Repeat for the next open issue: `GET /issues?state=open&type=issues` — note Gitea lists pull requests in this endpoint too; filter out entries with a `pull_request` key.
|
|
|
|
## 3. Gitea API + MCP quirks (learned the hard way)
|
|
- The gitea MCP tools work for issues/PRs/files/tags, and Actions endpoints work IF you pass owner=`OpenCode`, repo=`SpaceWanderer`. A wrong owner/repo makes EVERY call return `{"message":"not found","url":"https://git.kkhost.pl/api/swagger"}` — that swagger URL inside a 404 is the signature of "wrong path", not "Gitea is down".
|
|
- MCP merge endpoint 405s → don't bother; auto-merge handles merging. Manual fallback if ever needed: `POST /repos/OpenCode/SpaceWanderer/pulls/{n}/merge` with body `{"do":"merge","merge_style":"merge"}`.
|
|
- Gitea REST shapes (NOT GitHub's): list runs → `{workflow_runs:[...]}`; run jobs → `/actions/runs/{id}/jobs` returns `{"jobs":[...]}`; single job log via MCP `get_job_log_preview` (param tail_lines) or `download_job_log` to a file, then grep.
|
|
- Failure anatomy in CI logs: the Playwright summary at the end lists "N failed" + test titles; each failure block has a code frame with line numbers plus an "Error Context:" path. The e2e step is the only one that can fail flakily; unit failures are real regressions.
|
|
- CI watcher pattern that works: `run_background_process` (notify=true) running a loop that polls `GET /actions/runs/{id}` every 60 s and exits when status=completed, printing status+conclusion each tick. Don't poll in the foreground; don't sleep-loop on pty_read.
|
|
|
|
## 4. CI facts (.gitea/workflows/ci.yml + docker-compose.ci.yml)
|
|
- Mirrors Flight-Ops: single job "build + unit + e2e" on runner gitea-runner (docker-in-docker). Fresh DB per run (volume removed); compose project `space-wanderer-ci`; app container on a static IP → `E2E_BASE_URL=http://172.39.0.10:3000` (network `space-wanderer-ci-e2e`, subnet 172.39.0.0/24 — same mechanism as Flight-Ops, different network name so both can coexist on the shared daemon); `PW_REMOTE_BROWSER=0` (CI runs local chromium — the shared remote browser server at 192.168.1.4 cannot reach a stack inside dind); `E2E_COMPOSE_ARGS="-f docker-compose.ci.yml -p space-wanderer-ci"` is read by e2e/state.spec.ts for its mid-run `docker compose restart`.
|
|
- Flaky uplink → retry loops in ci.yml; an occasional "flaky" test (failed once, passed on retry) does NOT fail the run.
|
|
- Branch protection requires status check `CI / build + unit + e2e (pull request)` — PRs cannot merge until green; CI never deploys to production.
|
|
|
|
## 5. E2E conventions (e2e/*.spec.ts) — read before touching tests
|
|
- workers=1, serial in playwright.config.ts.
|
|
- **expect.poll callbacks must be total** — a throw inside fails the test instantly instead of retrying. Guard/filter everything you dereference.
|
|
- Deterministic dev hooks: `window.__*` exposed in dev builds + `/api/test/*` endpoints behind an env flag deliberately NOT set in prod.
|
|
- Turn-based game → actions resolve synchronously server-side, so tests are inherently more deterministic than Flight-Ops's real-time sim; no pause-sim pattern needed.
|
|
|
|
## 6. Game-specific gotchas
|
|
- None recorded yet — this is where hard-won knowledge accumulates as it is discovered. (Flight-Ops's equivalent sections documented Playwright evaluate serialization dropping prototype getters and MapLibre tile quantization — expect similar "the tool lies to you" surprises with whatever rendering approach lands.)
|
|
|
|
## 7. App architecture quick map
|
|
- **Scaffolded (v0.1.0)** — stack proof only, no game systems yet; the rest of this section is what's built + what lands next.
|
|
- Next.js 16 App Router + React 19 + TypeScript strict, bun package manager (bun.lock), Node 22 in CI/Docker.
|
|
- **Frontend component layer: scificn-ui v0.1.0** (https://scificn.dev) — copy-paste model on Radix + Tailwind v4; components live in `components/ui/` (Button, Panel, Badge, Card, Alert, Tabs, StatCard, Terminal, StatusGrid, ProgressRing, BarChart, LineChart, NodeGraph, Progress), theme tokens in `app/globals.css`. The app's interface base is the scificn-ui **Mission Control** showcase layout (https://www.scificn.dev/showcase/mission-control) rebuilt as `components/mission-control.tsx` and rendered from `app/page.tsx`, with placeholder ship content — no game logic yet. As of v0.2.0 the operations panel is a 7-tab visual template (WORLD MAP, LOCAL SYSTEM, CREW, SHIP SYSTEMS, SKILL TREE, MISSIONS, EVENT LOG) built on NodeGraph + Card widgets. As of v0.3.0 the WORLD MAP tab renders live data from `GET /api/world` (seeded world generation in `lib/game/`, save/jump/events via Drizzle/sql.js — single player, one save, no auth); the other tabs keep local placeholder constants until their own issues land. Deliberate deviation from upstream: `--text-muted` brightened `#4A4A40` → `#6B6B5C` (+12pt lightness) for readability on the near-black background. Upstream repo has **no LICENSE file** — user-approved risk, keep components minimal and re-verify licensing before any redistribution of this codebase.
|
|
- SQLite via Drizzle ORM + sql.js (WASM, kept external in next.config.ts) at db/space-wanderer.db volume-mounted; schema designed to switch to Postgres later. Game tables (`saves`, `solar_systems`, `jump_routes`, `events`) live since v0.3.0 — single-player save with seeded world generation + turn counter; DDL in `lib/db/client.ts` must stay in sync with `lib/db/schema.ts`.
|
|
- Vitest unit tests colocated (`**/*.test.ts`); Playwright e2e in `e2e/`, CI-only.
|
|
- Server-authoritative TURN engine in lib/ — unlike Flight-Ops there is NO tick loop or sim clock: state advances only when a player action resolves a turn, and every action endpoint returns the full post-action snapshot which the client applies immediately (polling optional/later for multiplayer).
|
|
- Plain React hooks for client state, no external store. **NO auth/accounts/multiplayer by design** (single player only) — there is no users/sessions table and no session headers; a "session" means the local single-player save slot in the DB, not an identity system. Do not copy Flight-Ops's lib/auth.ts / SignInScreen / admin patterns.
|
|
- Dev/e2e hooks: `window.__sw*` in dev builds + `/api/test/*` behind env flag not set in prod.
|
|
- Core game systems to build: turn engine, random encounter resolution, ship module grid (build/expand from found parts), resource management, crew with good/bad traits.
|
|
|
|
## 8. Finding current state (this file keeps no snapshots)
|
|
This manual is meant to stay valid long-term, so it deliberately contains NO version or issue snapshots — they rot. To orient yourself when you take over: `git log --oneline -10` + CHANGELOG.md for what has shipped; `GET /issues?state=open&type=issues` (filter out entries with a `pull_request` key) for what is left to do; PLAN.md's "Later" section for the roadmap backlog. Note: PLAN.md does not exist yet — it will be the game design doc.
|
|
|
|
## 9. Standing user instruction & etiquette
|
|
- The user's standing order for this project: work through the issue list autonomously — implement → PR → CI green → merge → tag → deploy prod → close with comment → next — until told to stop.
|
|
- Small incremental changes; each part fully tested (unit + e2e) before moving on.
|
|
- Long terminal tasks → pty_* tools (deploys, builds). Background watchers → run_background_process with notify=true.
|
|
- Never push directly to master; never deploy from a feature branch; CI never touches prod — production deploys are manual only (`docker compose up -d --build` after tagging).
|
|
- **Never commit credentials.** Tokens/secrets live in the MCP server config or with the user, never in tracked files (see incident note in §1).
|