v0.22.2 — commit ORCHESTRATOR.md manual #38
+7
-7
@@ -5,7 +5,7 @@ You are taking over the autonomous development loop on **Flight-Ops** (browser g
|
||||
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 **Flight-Ops** (full name `OpenCode/Flight-Ops`). ⚠️ NOT "krzysztof/flight" — that path 404s and caused a long dead-end in Sept 2026. Every Gitea API/MCP call uses owner=`OpenCode`, repo=`Flight-Ops`.
|
||||
- Repo: Gitea at https://git.kkhost.pl → org **OpenCode**, repo **Flight-Ops** (full name `OpenCode/Flight-Ops`). Every Gitea API/MCP call uses owner=`OpenCode`, repo=`Flight-Ops`.
|
||||
- Local workdir + prod deploy dir: `/home/krzyw/projects/sandbox/flight` (git checkout; `docker compose up -d --build` deploys from here).
|
||||
- Prod URL: https://flight.dev.kkhost.pl (Traefik → docker-compose stack on this host). `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 this 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.)
|
||||
@@ -14,7 +14,7 @@ Credentials are deliberately NOT stored in this file — see §1 for where they
|
||||
## 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 — precedent v0.19.1/v0.19.2).
|
||||
3. Local verification ONLY (there are NO local e2e runs): `npx tsc --noEmit`, `npx vitest run` (unit baseline: 288 tests in 31 files), `npx playwright test --list` (baseline: 41 tests in 12 files).
|
||||
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/flight && git checkout master && git reset --hard origin/master && docker compose up -d --build`; then verify `curl https://flight.dev.kkhost.pl/api/version` returns the new version and the root page is HTTP 200.
|
||||
@@ -41,19 +41,19 @@ Credentials are deliberately NOT stored in this file — see §1 for where they
|
||||
- `queryRenderedFeatures` is viewport-scoped → fitBounds/fitToAirports before asserting on far features; give the renderer ~300 ms after a camera jump.
|
||||
- **expect.poll callbacks must be total** — a throw inside fails the test instantly instead of retrying. Guard/filter everything you dereference.
|
||||
|
||||
## 6. ⚠️ The big one: Playwright evaluate serialization drops prototype getters (root cause of CI runs #69–#71)
|
||||
## 6. ⚠️ The big one: Playwright evaluate serialization drops prototype getters
|
||||
MapLibre's `queryRenderedFeatures` returns live `GeoJSONFeature` class instances whose `geometry` is a **lazy PROTOTYPE getter** (own properties are only type/properties/id/source/state plus private fields). Playwright serializes evaluate results by copying **own enumerable properties only**, so every feature arriving in test context has NO geometry — silently.
|
||||
- Verified empirically: `page.evaluate(() => { class A{constructor(){this.own=1} get geo(){return 42}} return [new A()] })` → `[{"own":1}]`.
|
||||
- Symptom matrix (how it masqueraded as "the line isn't drawn" while the trace rendered fine on screen): strict length guard → timeout; direct `.geometry.coordinates` access → `TypeError: Cannot read properties of undefined (reading 'coordinates')`; defensive filter → clean 15 s timeout.
|
||||
- Symptom matrix (how it masqueraded as "the line isn't drawn" while the trace rendered fine on screen, across three consecutive failed CI runs in Sept 2026): strict length guard → timeout; direct `.geometry.coordinates` access → `TypeError: Cannot read properties of undefined (reading 'coordinates')`; defensive filter → clean 15 s timeout.
|
||||
- **Rule: never return maplibre feature instances across page.evaluate — always map to plain objects in-page** (`{type, id, properties, geometry: f.geometry}` forces the getter to evaluate). Canonical pattern: `renderedFeatures()` in e2e/hover.spec.ts. Other specs that touch `.geometry` do so inside evaluate (safe) or only read array length (safe).
|
||||
|
||||
## 7. MapLibre rendering facts (for map assertions)
|
||||
- GeoJSON geometry is stored per-tile in INTEGER grids; long lines are clipped → `queryRenderedFeatures` returns ONE FEATURE PER TILE the line crosses (the EDDF→LEMD leg ≈ 4–5 segments at z=4/5).
|
||||
- Coordinates are quantized to the grid: error up to ~half a grid step (~0.001° observed at z≥4, worst ~0.02° at z=0 with extent 8192). Endpoint assertions must use an EPS (hover tests use `HOVER_ROUTE_EPS_DEG = 0.05` ≈ 5 km — above worst-case quantization at any zoom, below the distance between any two EU airports) and check endpoints ACROSS ALL SEGMENTS: some segment must START within EPS of origin AND some must END within EPS of destination. Never strict equality on a single feature.
|
||||
- Coordinates are quantized to the grid: error up to ~half a grid step (~0.001° observed at z≥4, worst ~0.02° at z=0 with extent 8192). Endpoint assertions must use an EPS sized for this (the hover tests define one in `expectHoverRoute` in e2e/hover.spec.ts — ~5 km: above worst-case quantization at any zoom, below the distance between any two EU airports) and check endpoints ACROSS ALL SEGMENTS: some segment must START within EPS of origin AND some must END within EPS of destination. Never strict equality on a single feature.
|
||||
- The true line endpoints survive clipping verbatim in whichever tile contains them.
|
||||
|
||||
## 8. App architecture quick map
|
||||
- `components/Map.tsx` — the MapLibre layer: sources/layers created in ensureLayers (dedicated `hover-routes` GeoJSON source + top-most dashed `hover-route` LineLayer, paint #facc15 width 4 dasharray [2,2]; `airports-target-highlight` green #4ade80 ring added last so it sits above the line at its endpoint); applyHoverRef re-pushes data on every hover; `window.__flightMap` dev hook.
|
||||
- `components/Map.tsx` — the MapLibre layer: sources/layers created in ensureLayers (dedicated `hover-routes` GeoJSON source + top-most dashed `hover-route` LineLayer, plus an `airports-target-highlight` ring layer added last so it sits above the line at its endpoint — current colors/widths live in Map.tsx, don't trust this doc for exact paint values); applyHoverRef re-pushes data on every hover; `window.__flightMap` dev hook.
|
||||
- `lib/mapData.ts` — pure GeoJSON builders (`hoverRouteGeoJson`, `routesGeoJson`, `greatCircleArc` slerp) + unit tests in lib/mapData.test.ts.
|
||||
- Hover protocol: panes report a HoverTarget via mouseenter/leave (`components/hoverTypes.ts`): `{kind:'plane';id} | {kind:'package';originIcao;destIcao;planeId?} | {kind:'route';fromIcao;toIcao}`; the `''` sentinel means no hover.
|
||||
- Server: sim ticks server-side, client polls /api/state; OpenAPI spec generated from lib/openapi.ts and served at /api/openapi — update it whenever an endpoint changes.
|
||||
@@ -66,4 +66,4 @@ This manual is meant to stay valid long-term, so it deliberately contains NO ver
|
||||
- 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).
|
||||
- **Never commit credentials.** Tokens/secrets live in the MCP server config or with the user, never in tracked files (see incident note in §1).
|
||||
Reference in New Issue
Block a user