1
0
Commit Graph

2 Commits

Author SHA1 Message Date
karti aab58a1c24 The client gets tests, starting with the two files that most needed them
Nine test files on the server, none on the client, and no test script in the
root package at all — so CI's only gate on the half of this project that runs in
a stranger's browser was `tsc --noEmit`, which will tell you the types line up
and nothing about whether an anonymous visitor is handed the private office.

Both files here were built to be tested and never were.

`access.ts` is the only module in the bundle whose output is a set of decisions
about what a stranger may see, and its own header carries the reason a test is
owed: a shipped line read `canEnterOffice = s.authenticated || !s.passwordLogin`,
which is true for `auth: none` and dangerously false for `sso` — where `POST
/session` answers 404 precisely *because* credentials are issued elsewhere — so
on an SSO deployment every anonymous visitor got the private view while the
config still said the box was private. There is now a test named after that bug.
The assertions are weighted toward the closed direction on purpose: one that a
member gets what a member is owed, and half a dozen that nobody gets more than
nothing, because showing a member the public office is a bad afternoon and
showing a stranger the private one is what the tiers exist to prevent. The 5xx
case is in there too — a box mid-restart is `anon`, not `member` — and so is the
`javascript:` entry URL, which a CSP of `script-src 'self' 'unsafe-inline'` does
not stop from navigating.

`plan.ts` says in its own header that it imports no three.js "so the splitting
pass is testable without a WebGL context", and that it "drops rather than
throws … every one of those is reported through `problems`" — an array whose
whole purpose is to be asserted on, which nothing asserted on. So: a pack wrong
in five ways still builds and files five reports; a zero-length wall does not
put a NaN in the bounds; an office with no levels stays finite so nothing
downstream divides by it; a pack with the required arrays missing is taken,
because HTTP will send one. And the wall pass gets the check CONTRACT.md §2's
argument deserves — one decomposition, two products — by walking a walker
through the door and into the wall beside it, and through a window and being
stopped. Also the yaw convention, which nothing stated and `officeMinimap.ts`
draws straight from: get the sign wrong and every wall mirrors about its own
centre, invisible on a square and obvious on anything else.

No new dependency. The server already runs `node --test` over `.ts` on native
type stripping, so the client does the same — which matters here, because this
repo's "no surprise dependencies" check is an allowlist naming why each one is
permitted, and a test runner would have needed an entry and an argument.

One source change was needed to make any of it possible. `session.ts` read
`import.meta.env.VITE_IDENTITY_URL` at module scope, and `access.ts` imports
`authFetch` from it — so one property access made the file that decides what an
anonymous visitor sees unreachable from a plain test runner, which is most of
why it had no tests. It now reads the way `plan.ts` already reads `DEV`, by the
idiom that file documents as being there "so this module stays importable from a
plain test runner".

31 tests, 9 suites, all passing, wired into `npm test` and into the CI job beside
the server's. `vite build` is unchanged and no test code reaches the bundle.
2026-08-06 03:46:17 -07:00
Karti Tripathi 44c5a79424 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>
2026-08-05 03:13:32 -07:00