Spaces: the inside of the world, and a sun that is actually where it should be
Ten agents wrote this in parallel against CONTRACT.md, which exists because the five design agents before them collided on fifteen blocking points — four files specified twice with incompatible contents, three separate backends for one box, and `Environment` exported twice meaning different things. What landed: a Stage owning only the renderer and the loop, with the city and an office as two scenes over it. They cannot share one — San Francisco is ~94 m per scene unit with 3.6x vertical exaggeration and an office is 1 unit = 1 m — and the city is paused rather than disposed on the way in, because rebuilding its 336,864-point heightfield costs about a second on the way back out. Offices are data. `src/offices/lumbridge-hq.ts` is fifteen rooms and seventy-six seats, and it is the file a self-hoster copies. Walls are a segment list with 1-D openings, so doors and windows are holes punched in a wall rather than placed objects, and the pass that splits a wall around its openings hands the walk-mode collider its segments for free. The sun is real. `solar.ts` is a NOAA/Meeus implementation with no imports at all — not even three.js — so time of day keeps working on a laptop in a field. Verified against known values: 75.45 degrees at the June solstice in SF, 28.79 at December, sunset at 03:15Z. The first screenshot after wiring it was a black rectangle, which turned out to be correct: it was midnight in San Francisco. Presence binds to a seat id and never to a coordinate. The pack knows where `eng-04` is; who is sitting in it is private data behind an API. Same shape as the marker rule, one level in. Two corrections to ARCHITECTURE.md are in here. Containment does not discharge ODbL — publishing OSM-derived coordinates is Public Use of a Derivative Database wherever the rows live, so the rule is about the geocoder (US Census, public domain) and not the storage. And a person at a desk is not a Marker; markers are geographic. One contract gap surfaced only in a screenshot: two agents read `height` on a viewpoint differently, so the establishing shot aimed at empty air fourteen metres above the roof. It now means what the same field means for a city. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* `GET /api/v1/flights`.
|
||||
*
|
||||
* Publicly cacheable, because the whole design of the plan is that one response
|
||||
* serves every viewer for its whole TTL. Aircraft are not personal data and this
|
||||
* body never varies by who asked.
|
||||
*/
|
||||
|
||||
import type { FastifyInstance } from "fastify";
|
||||
import { publicCache } from "../cache.ts";
|
||||
import type { Services } from "../services.ts";
|
||||
|
||||
export function registerFlights(app: FastifyInstance, services: Services): void {
|
||||
app.get("/api/v1/flights", async (req, reply) => {
|
||||
const body = await services.flights.current();
|
||||
publicCache(req, reply, body.ttlSeconds);
|
||||
return body;
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/**
|
||||
* `GET /api/v1/health`.
|
||||
*
|
||||
* The route the CI job asserts on, so it has one job: answer 200 on a box that
|
||||
* was handed nothing. It touches no upstream, reads no file and takes no lock —
|
||||
* a health check that can be made to fail by a third party's outage is a health
|
||||
* check that will page somebody at four in the morning about somebody else's
|
||||
* server.
|
||||
*
|
||||
* `degraded` is what makes it more than a liveness probe: every demotion the
|
||||
* config made is printed here, so "why is the weather always clear" has an
|
||||
* answer that does not require log access.
|
||||
*/
|
||||
|
||||
import type { FastifyInstance } from "fastify";
|
||||
import type { HealthBody } from "../../../src/server/wire.ts";
|
||||
import type { Services } from "../services.ts";
|
||||
|
||||
export function registerHealth(app: FastifyInstance, services: Services): void {
|
||||
const { config, startedAt } = services;
|
||||
|
||||
app.get("/api/v1/health", async () => {
|
||||
const body: HealthBody = {
|
||||
ok: true,
|
||||
service: "tera-api",
|
||||
version: config.version,
|
||||
uptimeSeconds: Math.round((Date.now() - startedAt) / 1000),
|
||||
sources: {
|
||||
weather: config.weather.source,
|
||||
flights: config.flights.source,
|
||||
markers: config.markers.source,
|
||||
},
|
||||
auth: {
|
||||
mode: config.auth.mode,
|
||||
entryUrl: config.auth.mode === "sso" && config.auth.entryUrl !== ""
|
||||
? config.auth.entryUrl
|
||||
: null,
|
||||
},
|
||||
degraded: config.degraded,
|
||||
};
|
||||
return body;
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* `GET /api/v1/markers`.
|
||||
*
|
||||
* The public snapshot, and nothing else. Private per-user markers are never
|
||||
* proxied through this box — an authenticated browser calls Workie directly with
|
||||
* its own token, so a private row never enters this process and cannot leave it.
|
||||
* CONTRACT.md §5.
|
||||
*
|
||||
* Every row served here has been through the provenance gate in `markers/gate.ts`,
|
||||
* which is what keeps a public snapshot from quietly becoming a Publicly Used
|
||||
* Derivative Database under ODbL.
|
||||
*/
|
||||
|
||||
import type { FastifyInstance } from "fastify";
|
||||
import { publicCache } from "../cache.ts";
|
||||
import type { Services } from "../services.ts";
|
||||
|
||||
export function registerMarkers(app: FastifyInstance, services: Services): void {
|
||||
app.get("/api/v1/markers", async (req, reply) => {
|
||||
const body = await services.markers.current();
|
||||
publicCache(req, reply, services.config.markers.ttlSeconds);
|
||||
return body;
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/**
|
||||
* `GET /api/v1/offices/:id`.
|
||||
*
|
||||
* The one authenticated route, and the one place the 404 rule matters: an office
|
||||
* the caller may not see answers **404, not 403**, and answers it identically to
|
||||
* an office that does not exist. A 403 is an existence oracle — walk the id space
|
||||
* and the status code tells you every tenant on the box. CONTRACT.md §6.
|
||||
*
|
||||
* The same reasoning is why the not-found path does no work first: resolve the
|
||||
* viewer, load the doc, and take one exit.
|
||||
*/
|
||||
|
||||
import type { FastifyInstance } from "fastify";
|
||||
import { publicCache } from "../cache.ts";
|
||||
import type { ErrorBody } from "../../../src/server/wire.ts";
|
||||
import type { Services } from "../services.ts";
|
||||
|
||||
const NOT_FOUND: ErrorBody = { error: "not_found", message: "No such office." };
|
||||
|
||||
export function registerOffices(app: FastifyInstance, services: Services): void {
|
||||
app.get<{ Params: { id: string } }>("/api/v1/offices/:id", async (req, reply) => {
|
||||
const doc = await services.offices.get(req.params.id);
|
||||
if (doc === null) return reply.code(404).send(NOT_FOUND);
|
||||
|
||||
if (doc.visibility === "private") {
|
||||
const viewer = await services.auth.resolve(req);
|
||||
if (!viewer.authenticated) return reply.code(404).send(NOT_FOUND);
|
||||
}
|
||||
|
||||
// Only a public office may be cached by anything shared. An unlisted one is
|
||||
// reachable by anybody holding the id, but it should not accumulate in a CDN
|
||||
// where the id is no longer needed to find it.
|
||||
if (doc.visibility === "public") publicCache(req, reply, services.config.publicMaxAge);
|
||||
|
||||
return doc;
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
* `GET /api/v1/weather`.
|
||||
*
|
||||
* Always 200, always a body. A source that is down, misconfigured or absent
|
||||
* produces `synthetic: true` and a clear day — there is no failure mode here in
|
||||
* which the caller has to decide what to render, because the answer to "what is
|
||||
* the sky doing" is never allowed to be a 503.
|
||||
*/
|
||||
|
||||
import type { FastifyInstance } from "fastify";
|
||||
import { publicCache } from "../cache.ts";
|
||||
import type { Services } from "../services.ts";
|
||||
|
||||
export function registerWeather(app: FastifyInstance, services: Services): void {
|
||||
app.get("/api/v1/weather", async (req, reply) => {
|
||||
const body = await services.weather.current();
|
||||
publicCache(req, reply, services.config.weather.ttlSeconds);
|
||||
return body;
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user