Uh oh!
There was an error while loading. Please reload this page.
Make the dev server say "npm install" instead of blaming read.tsx - #24
Conversation
Opening a document threw: [plugin:vite:import-analysis] Failed to resolve import "pdfjs-dist" from "src/read.tsx". Does the file exist? Nothing was wrong with read.tsx. `pdfjs-dist` is declared by apps/deliberation and recorded in the lockfile; it was simply not installed, because that node_modules predated the merge that added it. The overlay names a correct file, a correct line and a correct import, and asks whether a file the author never wrote exists - every fact in it points away from the cause. The trigger is not this package. It is any install older than the last dependency added on any branch, which is every collaborator after every pull, so the fix is not another install: it is a preflight that fails where the cause is legible. tools/check-deps.mjs walks the workspaces the root manifest declares and checks that what they declare is on disk, hoisted or nested. Exact pins are also version-checked, ranges are not: a bare version means somebody needed a specific one, and pdfjs-dist is pinned at 4.10.38 because 5.x needs node >= 22.13 and crashes on 20 - a stale hoisted 5.x would pass a directory check and then fail at runtime talking about something else. Ranges would need a semver implementation to say anything ranges do not already say. Wired into `npm run dev` in-process before any server is spawned, and into `deliberate:dev`; also `npm run check:deps` on its own. A guard that passes while checking nothing is the failure mode here, so the tests build broken fixture trees rather than running against this repo - gutting checkDeps to `return []` fails four of the eight. Two places where this could have gone quietly no-op are handled: the standalone-entry check uses pathToFileURL rather than interpolating argv[1], which on Windows never matches, and an unexpandable workspace pattern throws instead of skipping a workspace and still reporting ok. Verified: `npm run dev` exits 1 without spawning a server on a tree missing the package. 829 tests, typecheck and lint clean. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. 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 |
Written so the next session does not have to reconstruct this from a terminal. Sibling to HANDOFF-evaluation.md, added to this branch the same day from another session: that one owns the numbers, this one owns Read & mark, the environment behind it, and the dev-server preflight. WHAT IT CARRIES. The three load-bearing decisions in the reading surface and why each is easy to break: seats are stored rather than derived from participant order, because that order is a sorted set and adding anybody silently recoloured every existing highlight below them; the finding join is sourceDocumentId and not the filename, because real data holds "FDA NDA 211810" where the file is turalio-211810-multidiscipline.pdf and a filename join matches nothing while looking like a rendering bug; and blindness is enforced by the server not returning positions, so a new endpoint outside the read guard silently ends the blind stage. THE ONE PIECE OF THE DESIGN THAT IS NOT BUILT is written up as such - the top-level Read entry in the rail. It is no longer blocked on the scene, which now exists, and what it actually needs is a launcher route, because a NAV entry has no caseId to bind to. The seat palette question is left as a decision for a human rather than settled quietly in code. Re-fitting the seats to this branch's blue wedge separates them mostly by lightness, and 3 to 5 are close at badge size with six people on a case. Three ways out, all design-system calls. AN INDEX IN HANDOVER.md, because there were three branch handoffs and nothing pointed at any of them. HANDOVER.md is the file somebody opens first and it is only updated at merge, so work in flight was reachable only by knowing it existed. Corrected two claims while checking them rather than shipping them: the suite here is 821 tests across 58 files, not the 829/59 measured with PR #24's own tests included, and measure_pdf.py is in data/prep, not tools. Every file:line pointer in the document was verified against the tree. PR #24 is named as the first thing to do. It is not merged. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A second session is writing the reading-surface handoff on this same branch, and its first line is one this document was missing: HANDOVER.md records the submission as due 16 Aug 2026, which is today. A handoff that opens with a forty-minute measurement and says nothing about the deadline invites someone to start the EMA EPAR corpus work in section 8 instead, which has no chance of landing. So the deadline is now above section 0, with the note that the ordering survives it either way - after the date, the EPAR work stops being out of reach and becomes worth doing properly. Cross-referenced the sibling both directions. It owns the reading surface, the scene and the preflight; this one owns the numbers. Its first instruction is that PR #24 is open against this branch and unmerged, which matters to anyone arriving here cold and is not otherwise discoverable from this file. Section 13 gains what CI actually enforces, which is more than the three commands this document was quoting. The one that catches you is the manifest diff: a reported figure that moves fails the build until the move is committed and explained. Also that this branch has two sessions on it and the last push was rejected for exactly that - fetch before pushing. HANDOVER.md's index row for this file said "three times a metric looked broken". It is four; the fourth was my own fixture labels being wrong while the model was right, which is the one of the four most likely to repeat. Typecheck, lint and 821 tests pass. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…gful This branch's checks last ran against a base where npm test could not pass, so its red X was never about the preflight. Taking the base in so the run says something.
Uh oh!
There was an error while loading. Please reload this page.
The doc was written an hour before the merge it describes. Also note the gap it opened: #24 went to main alone, so feat/product-in-the-atmosphere is one merge behind again. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
main moved 42 commits under this branch - #33 (Postgres/Supabase), #24, #29, #32 and the logo - and rewrote the three files this touches most. THE RECONCILIATION #33 DEFERRED. `ShareStore` was written against the pattern this branch had: a synchronous `new ShareStore(path)` beside `AuthStore` and `InviteStore`. That layer is gone. So the store joins the new one the way the other four did: - `ShareStoreApi` in postgres-share.ts, where `AuthStoreApi` and `InviteStoreApi` live, for the reason stated there: the second implementation is what needs a name for the shape. - `ShareStore.open(path)`, async, private constructor. - `PostgresShareStore`, and supabase/migrations/0002_share_links.sql. - Both branches of `buildStores`, and `Stores.shares`. - The behaviour is ONE suite over both implementations (test/share-store-contract.ts), as with auth and invites. `shareSecret` deliberately stayed OUT of `buildStores`: which backing holds the links is a storage decision, whether the deployment can publish at all is not. THE TABLE HOLDS NO TOKEN, and the migration says so at length because that is the feature's whole security argument - the URL is HMAC(secret, "caseId:version"), derivable from two columns that are not secret, so a stolen dump yields nothing. `publish` omits `version` from its upsert's SET list on purpose: assigning it would reset a revoked case to 1 and re-mint the token revoke had just killed. A test reads the column list back out of information_schema, because that property fails silently. WHAT THE CONFLICTS COST. server.ts kept main's static serving whole and its `/api/health` route; the branch's "NO STATIC-FILE SERVING HERE" comment was true when written and is now a lie, so it is replaced by an accurate one: `/r/:caseId/:token` is still not served in production, a scanned QR 404s on a deployed host, and the two decisions that has to wait on are written down beside `staticRoot()`. Adding it here was out of scope and stayed out. `handleReport` and `handleShare` became async; `handleReport` fetches the people in one `auth.list()` rather than a lookup per name, because `auth.get` is asynchronous now and `buildCaseReport` takes a synchronous `person`. ONE THING THE MERGE HAD TO DECIDE. docs/HANDOFF-open-prs.md predicted that #30 and main each carried a provenance rule and that they would auto-merge without conflict. They did, and both were live: `view`'s read any unrecognised actor as `live`, the report's read only "model" as `live`. Two surfaces describing one signed safety adjudication, disagreeing about whether a model produced it. Closed with one module-level `sourceOf`, failing toward `stub`; every writer passes "stub" or "model" so nothing observable changed, and the test pins that both readers agree on a third actor neither was written for. The postgres test fixture now applies every migration in filename order. Pinned to 0001, it built a database that was correct on the day it was written and silently lacked share_links. Verified: lint, typecheck, 1267 tests with DATABASE_URL set (1179 without), both builds, harness + metrics + golden + an unchanged verdict-manifest, e2e. The public bundle still carries no auth code: only main's own entry chunk matches AUTO_PASSWORD or /api/auth/login, and public.html references neither. HANDOFF-pr34.md is deleted - the job it describes is this commit, and what happened is recorded in docs/HANDOFF-open-prs.md and the spec. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…, 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>
The report
Opening a document in Read & mark threw this:
Nothing was wrong with
read.tsx.pdfjs-distis declared byapps/deliberationand recorded inpackage-lock.json— it was simply never installed, because that checkout'snode_modulespredated the merge that added it.The overlay names a correct file, a correct line and a correct import, and asks whether a file the author never wrote exists. Every fact in it points away from the cause, so it sends you reading application source. It cost a round trip.
Why a preflight and not just an install
The trigger isn't this package. It's any
npm installolder than the last dependency added on any branch — which is every collaborator after every pull, forever. Installing once fixes today; this fixes the class.tools/check-deps.mjswalks the workspaces the root manifest declares and checks that what they declare is actually on disk, hoisted or nested:Same trade
dev-all.mjsalready makes with--strictPort: fail loudly at startup rather than proceed into a state whose symptom names the wrong cause.Exact pins are version-checked, ranges are not. A bare version means somebody needed a specific one —
pdfjs-distis pinned at 4.10.38 because 5.x needs Node ≥ 22.13 and crashes on 20. A stale hoisted 5.x would satisfy a directory check and then fail at runtime talking about something else, which is the exact failure mode this file exists to end. Ranges would need a semver implementation to say anything the range doesn't already say.Wiring
npm run dev— in-process, before a single server is spawnednpm run deliberate:devnpm run check:deps— standaloneTests
A guard's own failure mode is passing while checking nothing, so the suite builds broken fixture trees rather than running against this repo. Gutting
checkDepstoreturn []fails four of the eight.Two places this could have gone quietly no-op are closed:
pathToFileURLrather than interpolatingargv[1]into afile://string, which on Windows never matches — the script would have exited 0 having checked nothingVerified
npm run devon a tree with the package hidden: exits 1, no server spawneddependencies okBased on
feat/product-in-the-atmosphereso it can be merged into the branch being tested locally, without disturbing #22.🤖 Generated with Claude Code