SoCal, the whole bay, a moon, and gates that actually run
Six agents in parallel, and the two city packs independently reported the same blocker: `focusRegions` and `coarseFactor` existed on the `City` type and nothing implemented them. Uniform lattices would have been 2.9M points for Southern California and 3.7M for the expanded bay. Both packs were unloadable as written. `buildAxis` is the answer, and it is honest about its limits: refinement is per axis, not per rectangle, so a focus region sharpens its whole row *and* its whole column. Two regions at opposite corners refine nearly everything between them. Measured, not guessed — the bay went 0.53M points with one region and 1.64M with three, for detail nobody is looking at from a board this wide. One region each, coarse factor ten, and the builds land at 3.8 s and 2.3 s. Then three things that were only ever right because San Francisco was the only city. `maxDistance: 340` and a 170-unit shadow box were constants tuned for a 230-unit board; the bay is 1003 units across and the camera physically could not retreat far enough to frame it. Fog distances were scene units pinned to the same assumption. And `minVisibilityM` defaulted to 4.5 km of honest weather, which over ninety-four kilometres of bay correctly hides three quarters of it — the night view was a black rectangle for a completely reasonable reason. All three now derive from the board. The moon is a real ephemeris and its light is a deliberate lie: 1.15, against a physical ratio of one to four hundred thousand. What is being reproduced is what a moonlit night looks like on a screen in a lit room. The CI gate caught itself, which is the part worth keeping. Port 8431 was already held by a server from an earlier session, so the boot check polled a healthy stranger while the process it started died on EADDRINUSE. It now refuses to run rather than pass. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,119 @@
|
||||
# The gates.
|
||||
#
|
||||
# This repo makes two claims about itself — that it is Apache-2.0 clean, and that
|
||||
# a stranger can self-host it with no account, no key and no network — and until
|
||||
# this file existed nothing checked either one. Both had been verified per-lens,
|
||||
# in a unit test or by hand on a box that already had everything, and never once
|
||||
# end to end on an empty environment. A design critic put it exactly right:
|
||||
# until one of these jobs exists, self-hostable is a design intention, not a
|
||||
# property.
|
||||
#
|
||||
# Three jobs, one for each claim that can actually be measured:
|
||||
#
|
||||
# clean-clone a fresh checkout installs, builds and passes its tests
|
||||
# zero-config-boot the API answers health when handed nothing at all
|
||||
# no-binary-art src/** carries no committed binary assets
|
||||
#
|
||||
# They are deliberately independent and run in parallel: a broken build should
|
||||
# not hide a licensing regression.
|
||||
#
|
||||
# This runs on Gitea Actions, not GitHub. The syntax is GitHub-compatible and the
|
||||
# `actions/*` steps resolve through the instance's configured action registry.
|
||||
|
||||
name: gates
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [master]
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
|
||||
# A superseded push has nothing to tell us, and these jobs build a Docker image
|
||||
# and bind a port between them.
|
||||
concurrency:
|
||||
group: gates-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
# ---- Job 1: a stranger clones this and it works ----
|
||||
#
|
||||
# The whole job is the dev-kit promise from CONTRACT.md §0. Note what is absent
|
||||
# and is meant to stay absent: no `env:` block, no `secrets.*` anywhere, and no
|
||||
# dependency cache. The cache is the interesting omission — a warm cache would
|
||||
# make this job pass on a lockfile that no longer resolves from a clean state,
|
||||
# which is precisely the failure a stranger would hit first.
|
||||
clean-clone:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
# The server runs TypeScript directly by stripping types at load, so
|
||||
# the floor is real: server/package.json says >=22.18. 24 is what the
|
||||
# image in server/Dockerfile uses.
|
||||
node-version: "24"
|
||||
|
||||
- name: npm ci
|
||||
run: npm ci
|
||||
|
||||
- name: npm run build
|
||||
# tsc --noEmit, then vite build. A dynamic import of an uninstalled
|
||||
# package fails here, which is the reason the dependency policy is an
|
||||
# allowlist rather than a count — see CONTRACT.md §6.
|
||||
run: npm run build
|
||||
|
||||
- name: server tests
|
||||
run: npm test --workspace @lumbridge/tera-api
|
||||
|
||||
# ---- Job 2: the box boots on nothing ----
|
||||
#
|
||||
# Two independent server designs defaulted the weather source to a provider
|
||||
# that needs a contact string and then failed hard without one, which breaks
|
||||
# the only acceptance test this repo has. This job exists specifically to catch
|
||||
# that class of bug, and it passes today.
|
||||
#
|
||||
# The gate starts the real entry point under a genuinely empty environment
|
||||
# rather than `docker compose up`, which is the wording in CONTRACT.md §0. The
|
||||
# property asserted is identical — the compose file adds only TERA_HOST and
|
||||
# container hardening, and every other variable in it carries a `:-` default so
|
||||
# an empty environment resolves it to the empty string — while a job that needs
|
||||
# docker-in-docker present on the runner would be measuring the runner instead
|
||||
# of the repo. `node scripts/check-zero-config-boot.mjs --compose` runs the
|
||||
# literal compose form for anyone who has a Docker.
|
||||
zero-config-boot:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: "24"
|
||||
|
||||
- name: npm ci
|
||||
run: npm ci
|
||||
|
||||
- name: health on an empty environment
|
||||
run: node scripts/check-zero-config-boot.mjs
|
||||
|
||||
# ---- Job 3: no committed binary art ----
|
||||
#
|
||||
# Scoped strictly to tracked files under src/**, because a self-hoster is told
|
||||
# to put their own legally-clean art in public/props/ and friends and an
|
||||
# earlier design would have failed their build for doing exactly that. The
|
||||
# script enumerates with `git ls-files` and has no filesystem-walk fallback.
|
||||
# See CONTRACT.md §7.
|
||||
#
|
||||
# No install step: the check is dependency-free on purpose, so it stays
|
||||
# runnable by hand and cannot be broken by a bad lockfile.
|
||||
no-binary-art:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: "24"
|
||||
|
||||
- name: no binary art under src/
|
||||
run: node scripts/check-no-binaries.mjs
|
||||
Reference in New Issue
Block a user