Uh oh!
There was an error while loading. Please reload this page.
Fix the product's chrome: the reading tab, the call control, and the corner readout - #28
Closed
Darkest-Teddy wants to merge 7 commits into
Closed
Fix the product's chrome: the reading tab, the call control, and the corner readout#28Darkest-Teddy wants to merge 7 commits into
Darkest-Teddy wants to merge 7 commits into
Conversation
A server was running against this repo for hours answering source:"stub"
while a working key sat in .env. It was started from a second checkout - a
worktree under .claude/worktrees - which had neither the key support nor an env
file. Nothing in the banner could distinguish that from having no credentials,
because the banner never said which directory it resolved configuration
against. It does now.
The 503 body stays {"error":"no_key"}: spec section 10 pins it and three tests
assert the exact object. So the actionable half goes to the banner instead,
where the person starting the service reads it - naming the variable to set
rather than restating that something is absent. Four credential mechanisms
reach Gemini and "no credentials" narrowed it to none of them.
That silence is the same one that let GEMINI_API_KEY sit in a .env doing
nothing before the key path existed. Worth closing twice.
Verified against a directory with no env file, with a project but no ADC, and
with .env.share alone.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>I recommended it on a verification that used a simplified schema. The real ones do not look like that. generativelanguage.googleapis.com rejects `additionalProperties: false` outright - Unknown name "additionalProperties" at 'generation_config.response_schema' - and every schema in services/api sets it: adjudicate, ask, extract, interpret, navigate. So a deployment on that host answers unconstrained calls happily, prints LIVE, and fails on the first real adjudication. That failure mode is the argument for naming the endpoint in the banner rather than inferring "Vertex" from the model name, so the host stays reachable and is documented as unusable instead of removed - a misconfiguration worth being able to reproduce. Also records the billing precondition. An API key on a project with no billing account linked is free-tier only, 20 requests/minute shared across every holder, and Vertex refuses it outright. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The Library and Ask surfaces were empty for everyone but the machine that downloaded the PDFs. A fresh clone showed "This document cannot be searched - not in this checkout" on every entry, which reads as a broken product rather than a deliberate exclusion. Ask is the surface being demonstrated; a demonstration nobody else can run is not one. The rule this reverses said the files were retrievable from accessdata.fda.gov or ema.europa.eu "by the URL the spec records". No URL is recorded anywhere. library-sources.json carries filenames and an NDA number, there is no fetch script, and so retrieval meant hand-searching FDA's site for thirty-five documents. The stated escape hatch did not exist. 363 MB, accepted deliberately rather than by omission. Largest single file is 40.9 MB, inside GitHub's limit. Git LFS is the obvious next move if this becomes unwieldy - the files never change, which is exactly what LFS is for. All sixteen library entries now resolve. Fourteen are askable; tak994 has no source document, tolcapone is a scan with no extractable text, and troglitazone has no nonclinical chapter heading - content refusals the product is supposed to make, and a different fact from a missing file. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The Run-it section described accounts and configuration and said nothing about the Library, which was the surface a fresh clone actually found broken. It also now names the directory the banner prints, because a server started in a second checkout reading that checkout's configuration is the failure this repository produced twice in one day. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
"Your call" is the one irreversible control in the product - three options, sealed on submission - and it was rendering as a run of unstyled prose: AdvanceDo not advanceCannot conclude The markup asked for `.rail` wrapping `.persona` buttons. app.css defines neither. Both were real rules once, in the light stylesheet the product had before it went dark; the rewrite dropped them and left the two class names behind in screens.tsx, where nothing failed loudly because a class that matches no rule is not an error. No border, no ground, no gap, no pressed state - three buttons the width of their own text, touching. REPAIRED WITH THE PATTERN THIS APP ALREADY HAS rather than with two new rules. `.choice` wrapping `button.ghost[aria-pressed]` is what the finding editor and the new case form both use for a mutually exclusive set, and it carries the pressed state this control never had. No CSS was added - a fourth spelling of one control is how the first three drifted apart. `htmlFor="call"` went with them. A label's `for` names a form control and a div is not one, so the attribute resolved to nothing and the group had no accessible name at all. `role="group"` with `aria-labelledby` is the arrangement that actually carries "Your call" to a screen reader. The test asserts the pattern, not the class spelling, and separately asserts that neither dead name has come back. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The corner readout said ARCHIVE while the Section was drawing behind the reading surface, and CULTURE while the Helix closed over a record. The menu, at the same moment, lit DASHBOARD on a case's Record tab - disagreeing with the breadcrumb, the case title and the stage strip all at once. One cause. The chrome asks two different questions and had one answer between them: which PART OF THE PRODUCT you are in (the menu highlight) and which PLACE you are standing in (the corner). The corner read its name off whichever menu entry was lit, and two of the six environments have no menu entry - reading and the record are reached from inside a case, never from the menu - so both borrowed somebody else's name and announced the wrong world. This is the drift nav.ts opens by warning about, arriving from the side that note did not expect. Not a stale table: a table that never covered the case. `codename` was a field on the four menu entries, so it could only ever name four of six. Keyed by SCENE ID now, which is what the backdrop mounts, and read through `codenameFor(route)` -> `CODENAME[sceneFor(route)]`. The corner cannot say a different word from the scene that mounted, because it is asking the same function the backdrop asked. Adding a scene without a name is now the thing that shows up, rather than a wrong name that does not. The menu highlight stays a separate answer and is now complete: `record` was missing from the case-route list and fell through to the Dashboard, the single entry that is not where the reader is. Every stage of an open case lights the Library, the record included - it is the last stage of a case, not another part of the product. Tests are written against the two questions rather than the table, so they still mean something when the table is rewritten, and they check that every route the router can produce has a name at all. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Important Review skippedDraft detected. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
AndresL230 added a commit
that referenced
this pull request
Aug 17, 2026
… read Two fixes from #28, reimplemented against a main that has moved a long way under that branch rather than cherry-picked from it. THE CORNER READOUT. It read its name off whichever menu entry was lit, and that is a different question from which place the reader is standing in. Main had already fixed the half of this that reading suffered from - `read` has a menu entry now - but the record still has none, so it borrowed the Library's and the corner said ARCHIVE while the Helix closed over a sealed record. Measured before touching it: currentNav answered `Archive` for { name: "record" } while sceneFor mounted `record`, whose name is `Helix`. Keyed by scene id now and read through codenameFor(route) -> CODENAME[sceneFor(route)], so the corner asks the same function the backdrop asked and cannot say a different word. `codename` leaves NavItem: two tables holding one fact is what let them disagree. NOT read from the registry that owns those names, which is the obvious simplification and a bundle regression. scenes/registry.ts statically imports all seven scene factories and each imports three and gsap; Backdrop.tsx reaches the package through `await import()` for exactly that reason, and Chrome.tsx imports nav.ts eagerly. A static `import { STATES }` would put the 3D stack in the chunk that draws the sign-in screen. The duplication is paid for in nav.test.ts, which imports the registry for real and fails if the two drift - a test can afford the import, the shell cannot. THE CALL CONTROL'S NAME. `<label htmlFor="call">` pointed at `<div id="call">`. A label's `for` names a labelable form control and a div is not one, so the attribute resolved to nothing and the most consequential control in the product reached a screen reader with no accessible name. Nothing failed: an unmatched `for` is silent. role="group" with aria-labelledby is what actually carries "Your call" across. Seven tests, each checked against the broken state first: three fail on a wrong codename, three on the old label markup. 1131 passed / 72 files with Postgres and Storage up, typecheck 0, lint 0. #28 stays open. Everything else on it is either already on main or carries the two conflict traps recorded in docs/HANDOFF-open-prs.md. Co-Authored-By: Darkest-Teddy <hel.jack14@gmail.com> Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
AndresL230 added a commit
that referenced
this pull request
Aug 17, 2026
…was wrong The two live fixes are on main. Neither was cherry-pickable - main had independently fixed more than half of each, and both commits conflict now. The correction worth keeping: this document told the next reader to drop the local CODENAME table and read STATES from the atmosphere package instead. That is a bundle regression. The registry statically imports seven scene factories and each imports three and gsap, and nav.ts is in the eagerly-loaded shell chunk. The duplication is deliberate; a test pays for it. Advice that reads as obvious cleanup is exactly the kind worth writing down as refused. Also corrects the title, the count, and §1's claim that main and the atmosphere branch are identical. They were, at 0ad996e. They are 17 apart. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
AndresL230 added a commit
that referenced
this pull request
Aug 17, 2026
…, three fixes What this session actually did, and how each claim in it was checked. #25 reviewed from scratch, which nothing had done - its entry was a placeholder that said so. The ten numbers are sound: every headline re-derived from the raw rows rather than trusted, Wilson checked against the standard interval, the Ask/retrieval same-fixture cross-check confirmed real. Three defects in the instrument, all fixed: one headline was read from a summary field in the file that promises it never does that, one cross-check could not fire because the results file predates the field it keys off, and a product change to extraction retrieval rode along unmeasured by any of the ten and untested. #27 split; the good half is prepared. Also records a third blocker nobody had noted - it reverts SHAPE_ASK from 64000 to 16000 - and corrects "four eval scripts" to six. #28 verified empty against current main rather than asserted: five conflicts, all in files main has superseded. Two corrections to this document's own account of it, both from the same mistake - reading `git diff main PR` as if it were a merge. It is not: neither merge base contains `responseSchemaFor`, so main ADDED it and a merge keeps it. Corrects the no-database baseline, which was wrong by 7. 1055 + 76 = 1131 is the Postgres total; the recorded 1048 + 76 = 1124 was #33's merge-commit figure carried into a row it had stopped belonging to. New baselines at 1c25747 measured in both environments. Corrects the Node-20 note: CI pins node-version 22, and the real item is the action runtime. Records the dependabot triage, the two #24 risks now fixed, the withTransaction fix, and the .gitignore hole that let a venv symlink be committed during this session. Adds the two things this document keeps getting wrong: origin/main moves mid-session, and the open-PR count must come from `gh pr list` rather than from a sentence - it has now been miscounted twice in opposite directions, the second time omitting #34. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
AndresL230 added a commit
that referenced
this pull request
Aug 17, 2026
…se the queue `tools/seed-demo-documents.mjs --reset` deleted four paths under `results/` and printed "Store cleared". Since #33 the backing is chosen by DATABASE_URL in one place, and when it is set the record, accounts, invites and documents are in Postgres and Storage - so the delete hit files nobody was reading and the success line was a lie told to the one person who most needed the truth: whoever was about to re-seed. They would seed on top of everything still there, which is the duplicated-cases state the flag is usually reached for in the first place. It refuses now, rather than clearing Postgres itself. Deleting rows from a database this script never opened, on a URL it cannot verify is a demonstration deployment rather than a live one, is a worse failure than not doing it - and the log is hash-chained, so a partial delete is not something the product can be talked out of noticing later. It names the two migrations to re-apply and the bucket to empty instead. The guard is at the TOP of the file, above the fetch and the PyMuPDF gate. That placement is the substance of the fix, not tidiness: a Postgres host is the machine least likely to have 363 MB of PDFs or PyMuPDF on it, so the same check below the gate is unreachable from exactly the deployment that needs it - the run dies on a missing extractor instead. Checked both ways: with DATABASE_URL set it refuses and exits 1 having touched nothing; unset, it falls through to the ordinary file path. A tracked `.env.defaults` was considered here and REJECTED on second look, so no `.gitignore` negation was added. The mechanism already landed - env.ts reads the file when present - but there is nothing safe to put in it. #27's proposed models are not the ones the scoreboard was measured on and the six bare `loadEnv()` eval scripts would inherit them; `gemini-flash-latest` is a floating alias, worse again for reproducing a committed number. The models that ARE agreed are already in git as DEFAULT_ADJUDICATION_MODEL and DEFAULT_SHORT_MODEL with their measurement written out beside them, and a tracked file restating them is a second place for one fact to live. `.env.*` stays a blanket. Records the close of #27 and #28 and the deletion of feat/product-in-the-atmosphere, and what closing #27 gives up that is worth rebuilding: a fresh clone has the case content in git but nothing open, so the product looks empty and the data looks unshared. 1205 passed / 95 skipped without a database, 1300 passed / 0 skipped on Postgres and Storage - unchanged, as a tools-only change should be. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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 freeto 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.
Fixes the reported breakage: the format being wrong, backgrounds missing, colours missing, the top navigation naming the wrong place, and the read feature being gone.
What was actually wrong
The read feature was gone, and it took the background with it. Pressing Read & mark threw
atmosphere: unknown scene "read"out of a React effect. React unmounts a tree whose effect throws, so the whole product went blank — no chrome, no panels, no WebGL scene. Reproduced in the browser before the fix; the tree was empty (#roothad zero children) and two page errors were logged. Fixed onmainalready by "Register every scene the package has, not five of the seven"; this branch merges that in.Prose was sitting on a live WebGL field. The reading surface and the position form had no ground under them, so type ran straight over a moving scene. Also fixed on
main("Stand reading and answering on a plate"), merged here.The header sat across the text on a long page. Fixed on
main("Take the header up on the way down the page"), merged here."Your call" had lost its styling entirely. New in this branch. The most consequential control in the product — three options, sealed on submission — rendered as one line of unstyled prose:
AdvanceDo not advanceCannot conclude. It was written against.railand.persona, two classes the dark rewrite dropped fromapp.css. Repaired with the.choice+button.ghost[aria-pressed]pattern the app already uses in two other places, so no CSS was added. Its deadhtmlForpointing at a div is replaced with a realrole="group"/aria-labelledby.The chrome named the wrong place. New in this branch. The corner readout said ARCHIVE over the Section and CULTURE over the Helix, and the menu lit Dashboard on a case's Record tab. The corner took its name from whichever menu entry was lit, and reading and the record have no menu entry. Codenames are now keyed by scene id and read through
codenameFor(route), so the corner asks the same function the backdrop asks.Verification
npm run typecheck— cleannpm run lint— cleannpx vitest run— 860 passed, 63 filesNote on branches
This branch is the union of
mainandfeat/product-in-the-atmosphere. The three fixes above already onmainwere never onfeat/product-in-the-atmosphere, which is what was checked out and running.🤖 Generated with Claude Code