Gate production behind a deliberate release, and check a real model actually produces geometry - #119
Merged
Merged
Conversation
Merging a PR published to production. There was no gate between "approved" and "live", which is the single largest process risk in the repo. While changing it, a second and less obvious problem: `deploy.yml` and `ci.yml` both triggered on the same push to `main` and ran concurrently. Nothing made the deploy wait for the tests, and this build is faster than the e2e suite, so in practice production was published while `main`'s own CI was still running. A red main could reach users and usually would have. Publishing is now a tag (`v1.2.3`), which leaves a record of what shipped, or a manual `workflow_dispatch` against any ref. Neither implies tests ran — a tag can point at any commit — so a `guard` job looks up the completed CI run for that exact SHA and refuses anything that is not `success`, including "no CI run found", so an untested commit cannot be published by tagging it. Verified the guard's query against the live API: a known-green SHA returns "success", an unknown SHA returns empty and so fails closed. Rollback is the same mechanism against an older ref, which the guard permits because any previously-shipped commit already has its own green CI. Runbook updated, including why the push trigger should not be restored. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The headline feature had no end-to-end coverage. The wire is tested, the parser
is tested, and `chatStore.send.test.ts` joins them with both stubbed — so the
whole suite can be green while chat produces nothing a user can print. Two bugs
this year shipped through exactly that gap and were found by a person using the
app, not by the suite.
Adds `src/llm/live.test.ts`: the real system prompt, the real wire, the real
parser, asserting on evaluated geometry rather than on JSON shape. A reply can
parse perfectly and still describe an empty union, or a shape at the wrong
scale; bounds and field samples are what separate "the wire works" from "the
feature works".
Three cases, written against capability rather than exact output because the
subject is non-deterministic:
- "Make a 20mm cube" -> bounds are 20mm on every axis. The falsifiable one,
and it also catches the prompt failing to establish millimetres, which is
how this goes subtly wrong rather than obviously wrong.
- An L-bracket -> samples inside its own bounds are inside the solid, on a
5x5x5 grid rather than the centre, since an L's centre is fresh air.
- An edit to an existing box -> reaches the branch of the system prompt that
serialises the current tree, which no first-turn test touches, and checks
the untouched axis stayed put.
Skipped unless SINTER_LIVE_API_KEY is set, since it costs real money.
Verified it is not vacuous: with a deliberately bogus key all three fail with a
genuine 401 from OpenRouter, so the tests really do reach the network rather
than passing without running. Default `npm test` reports 3 skipped, suite green.
Runs weekly in CI rather than per-PR. What breaks this path is a provider
changing its wire format, a model drifting out of the requested response format,
or a credential expiring — none of which our own commits trigger, and a paid
third-party-dependent check on every PR gets disabled within a week. The job
fails loudly if the secret is missing, so an absent credential cannot read as a
pass.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
🚀 Preview deployed: https://ops-deploy-gate-and-live-llm.sinter.pages.dev (updates on every push to this PR) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The two things left open from the goal. Both are process/verification rather than features.
1. Merging to
mainwas a production releaseThere was no gate between "PR approved" and "live".
Changing it surfaced a second problem I hadn't spotted:
deploy.ymlandci.ymlboth triggered on the same push and ran concurrently. Nothing made the deploy wait for the tests, and this build is faster than the e2e suite — so in practice production was published whilemain's own CI was still running. A redmaincould reach users, and usually would have.Publishing is now:
Neither implies tests ran — a tag can point at any commit — so a
guardjob looks up the completed CI run for that exact SHA and refuses anything that isn'tsuccess, including "no CI run found". An untested commit can't be published by tagging it.Verified the guard's query against the live API before trusting it:
560b514(greenmain)success→ deploys0000000(nonexistent)Rollback is the same mechanism against an older ref; the guard allows it because any previously-shipped commit has its own green CI.
DEPLOY.mdupdated, including why the push trigger shouldn't be restored.This changes your workflow — merging no longer ships. That's the point, but it's the one thing here you may want to feel out before merging.
2. Nothing verified a real model produces geometry
The wire is tested, the parser is tested, and
chatStore.send.test.tsjoins them with both stubbed. So the entire suite can be green while chat produces nothing printable — which is how two bugs got to a user this year rather than to the suite.src/llm/live.test.tsuses the real system prompt, real wire and real parser, and asserts on evaluated geometry rather than JSON shape. A reply can parse perfectly and still describe an empty union or a shape at the wrong scale.Verified it isn't vacuous — a
skipIftest that never runs is worse than no test. With a deliberately bogus key, all three fail with a genuine 401 from OpenRouter, so they really do reach the network:Default
npm test: 503 passed | 3 skipped, green.Runs weekly, not per-PR — what breaks this path is a provider changing its wire format or a model drifting out of the requested format, neither of which our commits trigger, and a paid third-party-dependent check on every PR gets disabled within a week. The job fails loudly if the secret is missing, so an absent credential can't read as a pass.
What you need to do
To turn on the weekly run, add a repo secret
LIVE_LLM_API_KEY(OpenRouter by default). Until then the scheduled job will fail deliberately rather than pretend. You can also just run it locally:I can't run it against a real model myself — that needs your credits — so this PR proves the harness works, not that the feature does. The first real run is yours.
🤖 Generated with Claude Code