Skip to content

Researcher encrypted results#764

Merged
chrisbendel merged 61 commits into
mainfrom
researcher-encrypted-results
Jun 25, 2026
Merged

Researcher encrypted results#764
chrisbendel merged 61 commits into
mainfrom
researcher-encrypted-results

Conversation

@chrisbendel

@chrisbendel chrisbendel commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

Pairs with safeinsights/encryption#26

Test plan — researcher encrypted results

Setup — keys first (both at /account/keys, save PEM)

  • Reviewer (enclave user) key — needed before inject (script encrypts to it).
  • Researcher (lab user) key — needed before results-approve (re-wrap targets it).

Flow

  1. Researcher: create proposal → upload code → submit. → study PENDING-REVIEW, job CODE-SUBMITTED.
  2. Reviewer: open study → Approve proposal. → job CODE-APPROVED+JOB-READY, study APPROVED. (Code-approval gate. Do NOT skip — script's RUN-COMPLETE assumes it.)
  3. Grab jobId:
docker compose exec postgres psql -U mgmnt -d mgmnt_dev -c \
  "select sj.id, s.title from study_job sj join study s on s.id=sj.study_id order by sj.created_at desc limit 1;"
  1. Inject (= enclave runs + uploads encrypted results) → RUN-COMPLETE:
docker exec mgmnt-app pnpm exec tsx bin/inject-encrypted-results.ts <jobId>
  1. Reviewer: job page → decrypt (reviewer PEM) → Approve results → FILES-APPROVED + re-wrap fires.
  2. Researcher: results page → decrypt (researcher PEM) → results + logs visible/downloadable.

DB check after step 5

docker compose exec postgres psql -U mgmnt -d mgmnt_dev -c \
  "select file_path, fingerprint from study_job_file_key order by created_at desc;"

Expect 2 rows per researcher fingerprint: results.csv + run.log. Empty before approve.

Spot checks

  • Researcher sees results AND logs (all-or-nothing).
  • Wrong PEM → clean error.
  • Reject path → researcher sees rejected, no files.
  • Late-joiner: key made after approve → no rows, can't decrypt (no backfill).

Comment thread package.json Outdated
@chrisbendel chrisbendel marked this pull request as ready for review June 17, 2026 16:21

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the end-to-end “encrypted results” flow so that researchers can decrypt approved results/logs using their own key, without the server ever storing plaintext. It does this by having the reviewer decrypt artifacts in-browser, then re-wrap each inner file’s AES key to lab recipients and persist those wrapped keys in a new study_job_file_key table.

Changes:

  • Add server-side “re-wrap sharing” mechanism (study_job_file_key) and actions/queries to insert and read wrapped keys.
  • Rename “Reviewer Key” to role-neutral “Results Key” / “UserKey”, and extend key gating + permissions to lab researchers as well as enclave reviewers.
  • Refactor encrypted-file UI and decryption to operate on whole-zip artifacts, support researcher re-wrapped keys, and remove per-file selection (all-or-nothing share).

Reviewed changes

Copilot reviewed 66 out of 70 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
tests/study-flow.spec.ts Updates e2e flow copy/behavior for results-key wording and all-or-nothing sharing.
src/server/storage.ts Documents encrypted-results archive semantics; removes approved-plaintext storage helper.
src/server/results-sharing.ts New: validates + persists re-wrapped per-recipient AES keys (study_job_file_key).
src/server/results-sharing.test.ts Unit tests for sharing insert validation + idempotency.
src/server/db/queries.ts Renames key lookup; adds lab-key and shared-artifact queries; expands job file metadata.
src/server/db/queries.test.ts Updates tests for renamed key lookup and new shared-artifact query.
src/server/actions/user.actions.ts Renames redirect flag; gates key generation for any org that needs a key.
src/server/actions/user.actions.test.ts Adds test ensuring lab users without keys are redirected to key generation.
src/server/actions/user-keys.actions.ts Renames actions to UserKey; adds SPKI validation and broader revalidation.
src/server/actions/user-keys.actions.test.ts Updates tests for renamed actions and adds invalid-key rejection coverage.
src/server/actions/study.actions.ts Switches from uploading plaintext approved files to persisting wrapped-key rows.
src/server/actions/study-job.actions.ts Approve now inserts wrapped-key rows; adds actions to fetch lab keys and shared artifact ids; researcher fetch path supports wrapped keys.
src/server/actions/study-job.actions.test.ts Updates tests for encrypted-file fetching and researcher wrapped-key filtering.
src/server/actions/org.actions.ts Removes legacy reviewer-key action.
src/lib/types.ts Adds orgNeedsKey; introduces SharedFile schema; adds rawAesKey to decrypted entries.
src/lib/types.test.ts Adds unit tests for orgNeedsKey.
src/lib/routes/definitions.ts Renames route reviewerKeyuserKey.
src/lib/re-wrap-results.ts New: client-side re-wrap builder using lab public keys.
src/lib/permissions.ts Renames ability subject ReviewerKeyUserKey; grants key access to lab + enclave org members.
src/lib/permissions.test.ts Updates ability tests to assert UserKey access for reviewer + researcher roles.
src/lib/permission-types.ts Updates CASL subject union to UserKey.
src/lib/paths.ts Updates non-org route prefixes to include user-key.
src/lib/file-type-helpers.ts Removes legacy approved/encrypted conversion helpers; keeps mapping + labels.
src/hooks/use-profile-menu-disclosure.ts Pins Routes.userKey in profile menu.
src/hooks/use-encrypted-files-panel.ts Refactors encrypted-file panel state model to artifact-based view and shared-id lookup.
src/hooks/use-decrypt-files.ts Updates decryption to support whole-zip bodies + wrapped researcher keys; extracts raw AES keys for re-wrap.
src/database/types.ts Adds Kysely model/table entry for studyJobFileKey.
src/database/seeds/1743608138837_test_users.ts Seeds valid test public keys for key-required org members; computes fingerprint inline.
src/database/seed-test-public-key.test.ts Ensures embedded seed PEM matches tests/support/public_key.pem.
src/database/migrations/1780000000000_study_job_file_keys.ts Migration creating study_job_file_key with uniqueness on (artifact, inner path, fingerprint).
src/components/study/submitted-code-table.test.tsx Updates job-file fixtures to include id/path from expanded query.
src/components/require-user-key.tsx Renames + broadens key gate to lab + enclave orgs.
src/components/require-user-key.test.tsx Adds unit tests for researcher key-gating behavior.
src/components/require-reviewer-key.test.tsx Removes legacy reviewer-key gate test.
src/components/require-mfa.test.tsx Removes mocking of deleted legacy reviewer-key org action.
src/components/private-key-form.tsx New shared private-key entry form component (reviewer + researcher).
src/components/otp-input.tsx Adds autofocus to OTP input.
src/components/layout/navbar-profile-menu.tsx Renames nav item label to “Results Key” and points to /user-key.
src/components/layout/app-shell.tsx Switches app shell to new RequireUserKey gate.
src/components/job-results.tsx Replaces plaintext results UI with reusable encrypted panel for researchers.
src/components/encrypted-files-panel.tsx Removes per-file selection; uses shared PrivateKeyForm; updates status icons.
src/components/encrypted-files-panel.test.tsx Reworks tests around whole-zip artifacts + new placeholder copy.
src/app/user-key/regenerate-key.tsx New /user-key regeneration container.
src/app/user-key/regenerate-key.test.tsx Updates regeneration test for renamed action/copy.
src/app/user-key/regenerate-key-view.tsx Updates copy to “Results Key”; role-neutral key semantics.
src/app/user-key/regenerate-key-view.stories.tsx Updates story metadata/title for new page naming.
src/app/user-key/page.tsx Adds /user-key page.
src/app/user-key/layout.tsx Updates layout to use userKeyExistsAction and redirect to /account/keys if missing.
src/app/dl/results/[jobId]/[fileName]/route.ts Marks plaintext download route as legacy-only.
src/app/api/job/[jobId]/results/route.test.ts Adds regression test preventing results overwrite after completion.
src/app/account/signin/sign-in-form.tsx Uses new redirect flag for key generation.
src/app/account/signin/mfa.tsx Uses new redirect flag + invite join key requirement rename.
src/app/account/keys/page.tsx Uses userKeyExistsAction.
src/app/account/keys/generate-keys.tsx Renames copy/actions to “Results Key” and uses new user-key actions.
src/app/account/keys/generate-keys.test.tsx Updates tests for renamed key actions/copy.
src/app/account/invitation/[inviteId]/join-team/page.tsx Uses renamed needsUserKey flag.
src/app/account/invitation/[inviteId]/create-account.action.ts Renames key lookup and gates lab + enclave orgs via orgNeedsKey.
src/app/account/invitation/[inviteId]/create-account.action.test.ts Updates tests for new needsUserKey behavior (including lab org).
src/app/[orgSlug]/study/[studyId]/review/study-review-buttons.tsx Builds re-wrap payload client-side and submits as sharedFiles.
src/app/[orgSlug]/study/[studyId]/review/study-results.test.tsx Updates results tests for encrypted/shared key-based visibility.
src/app/[orgSlug]/study/[studyId]/review/study-results-redesign.tsx Removes legacy key label behavior; continues using encrypted panel.
src/app/[orgSlug]/study/[studyId]/review/study-results-redesign.test.tsx Updates placeholder text and encryption test harness.
src/app/[orgSlug]/study/[studyId]/review/job-review-buttons.tsx Approve now re-wraps and sends sharedFiles instead of plaintext job files.
src/app/[orgSlug]/study/[studyId]/review/job-review-buttons.test.tsx Updates approve test to assert re-wrapped key rows are persisted.
src/app/[orgSlug]/dashboard/page.test.tsx Removes mocking of deleted legacy reviewer-key org action.
pnpm-workspace.yaml Adds hono override to remediate a dev-only transitive vuln flagged by scanning.
pnpm-lock.yaml Locks updated hono and bumps si-encryption git ref.
package.json Bumps pnpm version and updates si-encryption dependency ref.
bin/inject-encrypted-results.ts New dev helper script to inject encrypted results and exercise the flow locally.
.npmrc Adds confirm-modules-purge=false.
Files not reviewed (1)
  • pnpm-lock.yaml: Generated file

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/server/actions/user-keys.actions.ts
Comment thread src/server/actions/user-keys.actions.ts
Comment thread src/components/layout/navbar-profile-menu.tsx
Comment thread src/hooks/use-encrypted-files-panel.ts
Comment thread src/hooks/use-encrypted-files-panel.ts Outdated

@nathanstitt nathanstitt left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see we're still storing the encrypted AES key that decodes the results in the DB for researchers vs in the zip like we do for reviewers.

It seems better to me to have a single way to store this, so either we store in the zip (reviewers), or in the db (researchers). Either has tradeoffs:

  • zip lets us have a single blob that is self-contained and easy to pass between systems
  • db row lets us potentially revoke access to a single user by deleting the row. However there's also other ways to revoke access, remove from org, or implement some other access rules.

I could be persuaded either way but think we should use the same mechanism for all users.

@@ -90,15 +90,15 @@ export function NavbarProfileMenu() {

<Protect role={AuthRole.Reviewer}>

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now that lab researchers hold a Results Key too (orgNeedsKey), this nav link is still gated behind <Protect role={AuthRole.Reviewer}> — so a researcher won't see "Results Key" in their profile menu. RequireUserKey covers the first-time generate redirect, but a researcher who already has a key has no menu entry to reach /user-key and regenerate it. Worth widening the Protect (or adding a Researcher-visible entry) so the rotate path is reachable for both roles.

'in',
encryptedFiles.map((f) => f.id),
)
.where('fingerprint', '=', userKey.fingerprint)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems important to solve:

Researcher access is keyed to userKey.fingerprint. If a researcher rotates their key (the update flow swaps the fingerprint), this filter stops matching the study_job_file_key rows wrapped against the old fingerprint, and they permanently lose access to already-approved results.

Is this intended?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Intended for now. Rotation swaps the fingerprint and orphans the old wrapped rows — the recovery path is the renewal/re-wrap flow (a teammate re-wraps for the new key), which is a separate workstream and not in this PR. Until it lands we're not surfacing self-rotate to researchers (first-time generate still works via the key-required redirect), and I'm filing renewal as the immediate follow-up. Tracking issue: .

.handler(async ({ studyJob }) => {
.handler(async ({ studyJob, session, db }) => {
const userKey = await getUserPublicKey(session.user.id)
if (!userKey) return []

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Small thing: getUserPublicKey does executeTakeFirst() over all of the user's rows, so if more than one userPublicKey row ever exists for a user the fingerprint chosen here is non-deterministic, which would silently mismatch the wrapped-key lookup below. Worth confirming there's a one-row-per-user invariant (unique constraint on user_id) backing this.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Backed by a constraint — user_public_key has unique_user_id (migration 1742320602314), so it's one row per user. executeTakeFirst is deterministic and setUserPublicKeyAction's insert can only ever be first-time. Rotation is update-in-place on that row.

@chrisbendel

Copy link
Copy Markdown
Contributor Author

I see we're still storing the encrypted AES key that decodes the results in the DB for researchers vs in the zip like we do for reviewers.

It seems better to me to have a single way to store this, so either we store in the zip (reviewers), or in the db (researchers). Either has tradeoffs:

* zip lets us have a single blob that is self-contained and easy to pass between systems

* db row lets us potentially revoke access to a single user by deleting the row.  However there's also other ways to revoke access, remove from org, or implement some other access rules.

I could be persuaded either way but think we should use the same mechanism for all users.

Fair push — and you're right that one source of truth matters. The thing is, on the read path it already is one: ResultsReader takes the DB-stored wrapped keys (additionalKeys, wired here as researcherKeys) and splices them into the manifest under the recipient's fingerprint before any decrypt. So decrypt is a single manifest.files[path].keys[fingerprint] lookup for everyone — there's no second code path, the DB rows just hydrate the same manifest the zip would've carried.

Where they differ is write timing, not mechanism:

Zip manifest = recipients that existed when the job ran in the enclave (reviewers). It's the immutable run artifact — we never rewrite it.
DB table = anyone granted access after run time. Researchers today; and per the lost-key / compromised-key / new-hire / departed-member thread, this is also where renewal re-wraps will land.
The two never hold the same recipient, so there's nothing to drift between — writes are disjoint, reads are the union. The reason it's a DB row and not "append to the zip" is that the post-hoc set is mutable and grows (renewals especially), and read-modify-writing the stored blob on every new grant means rewriting a large S3 object with no row-level concurrency control, plus it mutates the artifact TOA produced. A row with a unique constraint handles concurrency and revocation cleanly and leaves the run artifact untouched.

To make that intent obvious in the schema, I'll rename study_job_file_key → study_job_file_recipient_key (and the param researcherKeys → recipientKeys) so it reads as "post-hoc recipient keys, any role," not "the researcher special-case."

Decompose (pulling reviewer keys out of the zip into the DB too, so there's literally one store) is the other way to unify — but that's the version I just backed out of, and it means rewriting the prod ingest/decrypt path TOA depends on. Happy to revisit if you think single-store is worth that.

@chrisbendel chrisbendel requested a review from nathanstitt June 18, 2026 14:16

@nathanstitt nathanstitt left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your patience on this @chrisbendel - while I still think it'd be slightly better to have everything stored in the zip, I do see your reasoning for storing study-keys in the db. So I'm fine with it for now at least, we can easily revisit later if it does turn out to be an issue, but I doubt it will.

Thanks again!

@github-actions

Copy link
Copy Markdown
Contributor

Total coverage

Lines Branches Functions Statements
94.30% (+1.74%) 71.66% (+4.01%) 90.22% (+2.80%) 93.51% (+1.63%)

Detailed report

58 files with a coverage regression
File Lines Branches Functions Statements
src/app/[orgSlug]/admin/settings/code-env-form.tsx 100.00% (+6.25%) 62.06% (+6.89%) 58.33% (+12.88%) 97.36% (+6.46%)
src/app/[orgSlug]/admin/settings/code-envs-view.tsx 100.00% (+100.00%) 71.42% (+71.42%) 100.00% (+100.00%) 94.44% (+94.44%)
src/app/[orgSlug]/admin/settings/code-envs.actions.ts 60.38% (+0.25%) 37.07% 68.42% 60.00% (+0.26%)
src/app/[orgSlug]/admin/settings/code-envs.schema.ts 88.63% 64.00% 94.11% (+5.88%) 86.66%
🚫 src/app/[orgSlug]/admin/settings/code-envs.tsx 79.74% (-2.07%) 66.03% (+3.32%) 69.56% (-1.27%) 79.01% (-1.42%)
src/app/[orgSlug]/admin/settings/data-source-form.tsx 100.00% (+100.00%) 100.00% (+100.00%) 37.50% (+37.50%) 100.00% (+100.00%)
src/app/[orgSlug]/admin/settings/data-sources-view.tsx 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%)
src/app/[orgSlug]/admin/settings/data-sources.actions.ts 100.00% 100.00% (+25.00%) 100.00% 100.00%
src/app/[orgSlug]/admin/settings/data-sources.test.tsx 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%)
src/app/[orgSlug]/admin/settings/data-sources.tsx 100.00% (+100.00%) 69.23% (+69.23%) 90.00% (+90.00%) 100.00% (+100.00%)
src/app/[orgSlug]/admin/settings/use-code-env-form.ts 80.89% (+2.73%) 76.38% (+4.96%) 62.96% (+6.96%) 75.25% (+2.62%)
src/app/[orgSlug]/admin/settings/use-data-source-form.ts 79.41% (+79.41%) 90.00% (+90.00%) 60.00% (+60.00%) 79.41% (+79.41%)
src/app/[orgSlug]/admin/team/admin-users.actions.ts 93.75% (+0.21%) 83.33% 100.00% 93.75% (+0.21%)
src/app/[orgSlug]/study/[studyId]/_screens/code-decision-screen.tsx 100.00% (+100.00%) 70.00% (+70.00%) 100.00% (+100.00%) 84.21% (+84.21%)
src/app/[orgSlug]/study/[studyId]/_screens/code-under-review-screen.tsx 100.00% (+100.00%) 75.00% (+75.00%) 100.00% (+100.00%) 92.30% (+92.30%)
src/app/[orgSlug]/study/[studyId]/_screens/proposal-feedback-screen.tsx 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%)
src/app/[orgSlug]/study/[studyId]/_screens/registry.ts 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%)
src/app/[orgSlug]/study/[studyId]/_screens/render-screen.tsx 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%)
src/app/[orgSlug]/study/[studyId]/_screens/reviewer-agreements-screen.tsx 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%)
src/app/[orgSlug]/study/[studyId]/_screens/reviewer-code-feedback-screen.tsx 89.47% (+89.47%) 60.00% (+60.00%) 100.00% (+100.00%) 89.47% (+89.47%)
src/app/[orgSlug]/study/[studyId]/_screens/reviewer-code-review-screen.tsx 90.90% (+90.90%) 50.00% (+50.00%) 100.00% (+100.00%) 90.90% (+90.90%)
src/app/[orgSlug]/study/[studyId]/_screens/reviewer-proposal-feedback-screen.tsx 92.85% (+92.85%) 66.66% (+66.66%) 100.00% (+100.00%) 92.85% (+92.85%)
src/app/[orgSlug]/study/[studyId]/_screens/reviewer-proposal-review-screen.tsx 92.30% (+92.30%) 50.00% (+50.00%) 100.00% (+100.00%) 92.30% (+92.30%)
src/app/[orgSlug]/study/[studyId]/_screens/reviewer-study-results-screen.tsx 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%)
src/app/[orgSlug]/study/[studyId]/_screens/study-overview-screen.tsx 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%)
src/app/[orgSlug]/study/[studyId]/_screens/study-results-screen.tsx 100.00% (+100.00%) 50.00% (+50.00%) 100.00% (+100.00%) 87.50% (+87.50%)
🚫 src/app/[orgSlug]/study/[studyId]/agreements/agreements-page.tsx 100.00% (+10.00%) 88.88% (-11.12%) 100.00% (+20.00%) 100.00% (+10.00%)
🚫 src/app/[orgSlug]/study/[studyId]/agreements/page.tsx 91.17% (-6.19%) 77.77% (-15.08%) 100.00% 91.17% (-3.70%)
src/app/[orgSlug]/study/[studyId]/edit/page.test.tsx 97.43% (+97.43%) 100.00% (+100.00%) 87.50% (+87.50%) 97.43% (+97.43%)
src/app/[orgSlug]/study/[studyId]/edit/page.tsx 100.00% (+100.00%) 83.33% (+83.33%) 100.00% (+100.00%) 100.00% (+100.00%)
src/app/[orgSlug]/study/[studyId]/edit-and-resubmit/edit-initial-request-section.tsx 46.87% (+46.87%) 0.00% 0.00% 46.87% (+46.87%)
src/app/[orgSlug]/study/[studyId]/edit-and-resubmit/footer.test.tsx 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%)
src/app/[orgSlug]/study/[studyId]/edit-and-resubmit/footer.tsx 80.64% (+80.64%) 66.66% (+66.66%) 33.33% (+33.33%) 78.12% (+78.12%)
src/app/[orgSlug]/study/[studyId]/edit-and-resubmit/form.tsx 75.00% (+75.00%) 100.00% (+100.00%) 0.00% 75.00% (+75.00%)
src/app/[orgSlug]/study/[studyId]/edit-and-resubmit/page.test.tsx 100.00% (+100.00%) 50.00% (+50.00%) 100.00% (+100.00%) 100.00% (+100.00%)
src/app/[orgSlug]/study/[studyId]/edit-and-resubmit/page.tsx 100.00% (+100.00%) 64.28% (+64.28%) 100.00% (+100.00%) 87.09% (+87.09%)
src/app/[orgSlug]/study/[studyId]/edit-and-resubmit/schema.test.ts 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%)
src/app/[orgSlug]/study/[studyId]/edit-and-resubmit/schema.ts 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%)
src/app/[orgSlug]/study/[studyId]/proposal/collaborative-proposal-text-field.tsx 52.63% (+52.63%) 0.00% 0.00% 52.63% (+52.63%)
src/app/[orgSlug]/study/[studyId]/proposal/field-config.ts 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%)
src/app/[orgSlug]/study/[studyId]/proposal/footer.test.tsx 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%)
src/app/[orgSlug]/study/[studyId]/proposal/footer.tsx 86.20% (+86.20%) 73.33% (+73.33%) 33.33% (+33.33%) 83.33% (+83.33%)
src/app/[orgSlug]/study/[studyId]/proposal/reviewer-preview.tsx 58.82% (+58.82%) 0.00% 0.00% 58.82% (+58.82%)
src/app/[orgSlug]/study/[studyId]/resubmit/edit-study-code-footer.test.tsx 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%)
src/app/[orgSlug]/study/[studyId]/resubmit/edit-study-code-footer.tsx 80.64% (+80.64%) 62.50% (+62.50%) 50.00% (+50.00%) 73.52% (+73.52%)
src/app/[orgSlug]/study/[studyId]/resubmit/edit-study-code-view.tsx 83.33% (+83.33%) 100.00% (+100.00%) 0.00% 83.33% (+83.33%)
src/app/[orgSlug]/study/[studyId]/resubmit/page.test.tsx 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%)
src/app/[orgSlug]/study/[studyId]/resubmit/page.tsx 96.15% (+96.15%) 73.33% (+73.33%) 100.00% (+100.00%) 92.85% (+92.85%)
src/app/[orgSlug]/study/[studyId]/review/code-evaluation-section.test.tsx 100.00% (+100.00%) 50.00% (+50.00%) 100.00% (+100.00%) 97.29% (+97.29%)
src/app/[orgSlug]/study/[studyId]/review/code-evaluation-section.tsx 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%)
src/app/[orgSlug]/study/[studyId]/review/code-review-client.test.tsx 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%)
src/app/[orgSlug]/study/[studyId]/review/code-review-client.tsx 100.00% (+100.00%) 80.95% (+80.95%) 100.00% (+100.00%) 95.23% (+95.23%)
src/app/[orgSlug]/study/[studyId]/review/code-review-criteria.ts 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%)
src/app/[orgSlug]/study/[studyId]/review/code-review-feedback-section.tsx 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%)
src/app/[orgSlug]/study/[studyId]/review/code-review-submission-listener.tsx 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%)
src/app/[orgSlug]/study/[studyId]/review/code-review.test.tsx 100.00% (+100.00%) 62.96% (+62.96%) 100.00% (+100.00%) 99.09% (+99.09%)
src/app/[orgSlug]/study/[studyId]/review/code-review.tsx 97.61% (+97.61%) 77.77% (+77.77%) 100.00% (+100.00%) 95.55% (+95.55%)
src/app/[orgSlug]/study/[studyId]/review/job-review-buttons.tsx 100.00% 95.83% 100.00% 97.29% (+0.15%)
🚫 src/app/[orgSlug]/study/[studyId]/review/page.test.tsx 100.00% 50.00% (-50.00%) 100.00% 100.00%
🚫 src/app/[orgSlug]/study/[studyId]/review/page.tsx 100.00% (+7.32%) 75.00% (-9.61%) 100.00% 93.75% (+3.28%)
🚫 src/app/[orgSlug]/study/[studyId]/review/post-feedback-view.test.tsx 100.00% 95.00% (-5.00%) 95.65% (-4.35%) 99.05% (-0.95%)
src/app/[orgSlug]/study/[studyId]/review/post-feedback-view.tsx 100.00% (+3.34%) 89.28% (+14.28%) 100.00% 98.03% (+1.37%)
src/app/[orgSlug]/study/[studyId]/review/proposal/page.test.tsx 95.83% (+95.83%) 100.00% (+100.00%) 83.33% (+83.33%) 95.83% (+95.83%)
src/app/[orgSlug]/study/[studyId]/review/proposal/page.tsx 100.00% (+100.00%) 66.66% (+66.66%) 100.00% (+100.00%) 90.00% (+90.00%)
src/app/[orgSlug]/study/[studyId]/review/proposal-review-layout-view.tsx 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%)
🚫 src/app/[orgSlug]/study/[studyId]/review/proposal-review-view.test.tsx 100.00% 50.00% (-50.00%) 83.33% (-16.67%) 98.92% (-1.08%)
🚫 src/app/[orgSlug]/study/[studyId]/review/proposal-review-view.tsx 83.92% (+0.59%) 33.33% (-13.72%) 62.50% 83.92% (+0.59%)
🚫 src/app/[orgSlug]/study/[studyId]/review/proposal-section.test.tsx 100.00% 72.00% (+22.00%) 100.00% 99.06% (-0.94%)
src/app/[orgSlug]/study/[studyId]/review/proposal-section.tsx 100.00% 91.66% (+25.00%) 100.00% 100.00%
🚫 src/app/[orgSlug]/study/[studyId]/review/review-decision-section.test.tsx 100.00% 66.66% (-33.34%) 100.00% 98.50% (-1.50%)
src/app/[orgSlug]/study/[studyId]/review/review-submission-listener.tsx 100.00% (+34.62%) 100.00% (+75.00%) 100.00% (+60.00%) 100.00% (+33.34%)
src/app/[orgSlug]/study/[studyId]/review/reviewer-page-guard.tsx 95.23% (+95.23%) 83.33% (+83.33%) 100.00% (+100.00%) 91.66% (+91.66%)
src/app/[orgSlug]/study/[studyId]/review/study-code-files.test.ts 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%)
src/app/[orgSlug]/study/[studyId]/review/study-code-files.ts 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%)
src/app/[orgSlug]/study/[studyId]/review/study-details-reviewer-view.tsx 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%)
src/app/[orgSlug]/study/[studyId]/review/study-details-reviewer.test.tsx 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%)
src/app/[orgSlug]/study/[studyId]/review/study-details-reviewer.tsx 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%)
src/app/[orgSlug]/study/[studyId]/review/study-results-redesign-with-review.tsx 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%)
src/app/[orgSlug]/study/[studyId]/review/study-results-redesign.test.tsx 100.00% (+100.00%) 50.00% (+50.00%) 92.85% (+92.85%) 100.00% (+100.00%)
src/app/[orgSlug]/study/[studyId]/review/study-results-redesign.tsx 100.00% (+100.00%) 92.30% (+92.30%) 100.00% (+100.00%) 100.00% (+100.00%)
🚫 src/app/[orgSlug]/study/[studyId]/review/study-results.test.tsx 100.00% 50.00% 95.23% (-4.77%) 100.00%
🚫 src/app/[orgSlug]/study/[studyId]/review/study-results.tsx 85.00% (-7.68%) 78.57% (-10.71%) 71.42% (-28.58%) 85.00% (-7.68%)
🚫 src/app/[orgSlug]/study/[studyId]/review/study-review-buttons.tsx 100.00% 82.60% (-3.11%) 100.00% 100.00%
src/app/[orgSlug]/study/[studyId]/review/submitted-code-interactive.tsx 99.13% (+99.13%) 95.83% (+95.83%) 97.72% (+97.72%) 97.65% (+97.65%)
src/app/[orgSlug]/study/[studyId]/review/submitted-code-section.test.tsx 100.00% (+100.00%) 90.90% (+90.90%) 100.00% (+100.00%) 100.00% (+100.00%)
src/app/[orgSlug]/study/[studyId]/review/submitted-code-section.tsx 96.66% (+96.66%) 90.90% (+90.90%) 100.00% (+100.00%) 96.66% (+96.66%)
🚫 src/app/[orgSlug]/study/[studyId]/submitted/proposal-submitted.test.tsx 100.00% 85.71% (+26.89%) 100.00% 99.48% (-0.52%)
src/app/[orgSlug]/study/[studyId]/submitted/proposal-submitted.tsx 97.05% (+0.63%) 84.21% (+17.55%) 100.00% 94.59% (+1.26%)
src/app/[orgSlug]/study/[studyId]/view/code-post-decision-view.test.tsx 100.00% (+100.00%) 89.65% (+89.65%) 92.10% (+92.10%) 99.41% (+99.41%)
src/app/[orgSlug]/study/[studyId]/view/code-post-decision-view.tsx 100.00% (+100.00%) 86.66% (+86.66%) 100.00% (+100.00%) 100.00% (+100.00%)
src/app/[orgSlug]/study/[studyId]/view/code-post-submission-view.test.tsx 100.00% (+100.00%) 81.81% (+81.81%) 100.00% (+100.00%) 100.00% (+100.00%)
src/app/[orgSlug]/study/[studyId]/view/code-post-submission-view.tsx 100.00% (+100.00%) 93.10% (+93.10%) 100.00% (+100.00%) 98.07% (+98.07%)
src/app/[orgSlug]/study/[studyId]/view/job-results-status-message-view.tsx 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%)
src/app/[orgSlug]/study/[studyId]/view/load-code-review-feedback.ts 100.00% (+100.00%) 50.00% (+50.00%) 100.00% (+100.00%) 100.00% (+100.00%)
🚫 src/app/[orgSlug]/study/[studyId]/view/page.test.tsx 100.00% 75.00% (-25.00%) 100.00% 100.00%
🚫 src/app/[orgSlug]/study/[studyId]/view/page.tsx 100.00% 83.33% (-16.67%) 100.00% 93.75% (-6.25%)
🚫 src/app/[orgSlug]/study/[studyId]/view/researcher-proposal-view.tsx 100.00% 100.00% 66.66% (-33.34%) 100.00%
src/app/[orgSlug]/study/[studyId]/view/study-code-collapse.tsx 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%)
src/app/[orgSlug]/study/[studyId]/view/study-details-researcher-view.tsx 100.00% (+100.00%) 50.00% (+50.00%) 100.00% (+100.00%) 100.00% (+100.00%)
src/app/[orgSlug]/study/[studyId]/view/study-details-researcher.test.tsx 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%)
src/app/[orgSlug]/study/[studyId]/view/study-details-researcher.tsx 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%)
src/app/[orgSlug]/study/request/page-header.tsx 100.00% (+14.29%) 100.00% 100.00% (+50.00%) 100.00% (+14.29%)
src/app/[orgSlug]/study/request/proposal-footer-actions.tsx 100.00% (+100.00%) 60.00% (+60.00%) 50.00% (+50.00%) 100.00% (+100.00%)
src/app/[orgSlug]/study/request/proposal.tsx 67.74% (+67.74%) 30.00% (+30.00%) 33.33% (+33.33%) 65.62% (+65.62%)
src/app/account/invitation/[inviteId]/create-account.action.test.ts 100.00% 100.00% 89.47% (+1.97%) 100.00%
src/app/account/invitation/[inviteId]/create-account.action.ts 78.94% (+5.81%) 53.57% (+7.42%) 80.00% 78.94% (+5.81%)
src/app/admin/safeinsights/agent-context.test.tsx 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%)
src/app/admin/safeinsights/agent-context.tsx 93.54% (+93.54%) 66.66% (+66.66%) 88.88% (+88.88%) 93.75% (+93.75%)
🚫 src/app/api/job/[jobId]/results/route.test.ts 98.11% (-1.89%) 100.00% 85.71% (-14.29%) 98.11% (-1.89%)
src/app/api/job/[jobId]/results/route.ts 89.28% 85.00% (+5.00%) 100.00% 89.65% (+3.45%)
src/app/dashboard/user-studies.test.tsx 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%)
src/app/dashboard/user-studies.tsx 100.00% (+100.00%) 95.00% (+95.00%) 100.00% (+100.00%) 96.96% (+96.96%)
src/app/layout.stylesheet-parity.test.ts 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%)
src/app/user-key/regenerate-key-view.tsx 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%)
src/app/user-key/regenerate-key.test.tsx 100.00% (+100.00%) 100.00% (+100.00%) 85.71% (+85.71%) 100.00% (+100.00%)
src/app/user-key/regenerate-key.tsx 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%)
🚫 src/components/activity-context.tsx 53.48% (-2.61%) 14.28% (-2.38%) 57.14% 53.48% (-2.61%)
src/components/dashboard/studies-table/columns.tsx 100.00% (+8.34%) 100.00% (+33.34%) 100.00% 100.00% (+8.34%)
src/components/dashboard/studies-table/dashboard-raw-state.test.ts 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%)
src/components/dashboard/studies-table/dashboard-raw-state.ts 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%)
src/components/dashboard/studies-table/delete-draft-button.test.tsx 100.00% (+100.00%) 50.00% (+50.00%) 100.00% (+100.00%) 100.00% (+100.00%)
src/components/dashboard/studies-table/delete-draft-button.tsx 100.00% (+100.00%) 75.00% (+75.00%) 100.00% (+100.00%) 100.00% (+100.00%)
src/components/dashboard/studies-table/empty-state.tsx 100.00% 100.00% (+75.00%) 100.00% 100.00%
src/components/dashboard/studies-table/index.tsx 100.00% (+18.87%) 100.00% (+45.91%) 100.00% (+36.37%) 100.00% (+18.52%)
src/components/dashboard/studies-table/studies-table-view.tsx 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%)
src/components/dashboard/studies-table/studies-table.test.tsx 100.00% 100.00% 87.50% (+7.50%) 100.00%
src/components/dashboard/studies-table/study-action-link.tsx 100.00% 81.25% (+2.68%) 100.00% 100.00%
src/components/dashboard/studies-table/study-row-view.tsx 100.00% (+100.00%) 92.85% (+92.85%) 100.00% (+100.00%) 100.00% (+100.00%)
src/components/dashboard/studies-table/study-row.test.tsx 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%)
src/components/dashboard/studies-table/study-row.tsx 100.00% (+4.77%) 100.00% (+23.53%) 100.00% 100.00% (+4.77%)
src/components/dataset-multi-select.tsx 17.85% (+17.85%) 0.00% 0.00% 17.24% (+17.24%)
src/components/download-blob-link.test.tsx 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%)
src/components/download-blob-link.tsx 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%)
src/components/editable-text/collaborative-editor.tsx 79.20% (+1.14%) 61.95% (+15.18%) 69.56% (+5.68%) 77.02% (+1.42%)
src/components/editable-text/editor.test.tsx 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%)
src/components/editable-text/editor.tsx 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%)
src/components/editable-text/single-user-editor.test.tsx 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%)
src/components/editable-text/single-user-editor.tsx 100.00% (+100.00%) 80.00% (+80.00%) 83.33% (+83.33%) 96.77% (+96.77%)
src/components/editable-text/toolbar.tsx 52.63% 23.33% (+6.67%) 25.00% 50.00%
src/components/editable-text/use-active-editors.test.ts 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%)
src/components/editable-text.tsx 43.75% (+43.75%) 0.00% 0.00% 43.75% (+43.75%)
src/components/encrypted-files-panel.test.tsx 100.00% 100.00% 97.29% (+3.18%) 100.00%
src/components/encrypted-files-panel.tsx 100.00% 100.00% 100.00% (+10.00%) 100.00%
🚫 src/components/errors.tsx 61.11% (+3.97%) 52.63% (-0.31%) 70.00% 63.15% (+2.63%)
🚫 src/components/file-chip.tsx 45.45% (-46.21%) 0.00% (-50.00%) 0.00% (-100.00%) 45.45% (-46.21%)
src/components/file-viewers/code-viewer.tsx 97.40% (+97.40%) 75.00% (+75.00%) 100.00% (+100.00%) 97.43% (+97.43%)
🚫 src/components/file-viewers/csv-viewer.tsx 100.00% 62.50% 100.00% 90.90% (-0.76%)
src/components/file-viewers/index.tsx 90.90% (+2.02%) 100.00% 100.00% 91.66% (+1.66%)
🚫 src/components/file-viewers/log-viewer.tsx 62.50% (-4.16%) 50.00% 33.33% 66.66% (-3.34%)
src/components/form-field-label.tsx 81.81% (+1.81%) 60.00% (+14.55%) 100.00% 81.81% (+1.81%)
src/components/job-results.tsx 100.00% (+20.94%) 100.00% (+50.00%) 100.00% (+16.67%) 100.00% (+22.23%)
src/components/layout/app-footer.tsx 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%)
src/components/layout/focused-layout-shell-view.tsx 100.00% (+100.00%) 25.00% (+25.00%) 50.00% (+50.00%) 100.00% (+100.00%)
src/components/layout/focused-layout-shell.tsx 100.00% 100.00% (+50.00%) 50.00% 100.00%
src/components/layout/skeleton/dashboard.tsx 84.61% (+23.08%) 100.00% (+33.34%) 83.33% (+16.67%) 84.61% (+23.08%)
🚫 src/components/loading.tsx 100.00% 50.00% 100.00% 80.00% (-3.33%)
src/components/modals/app-modal.tsx 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%)
src/components/modals/file-preview-modal.test.tsx 100.00% (+100.00%) 100.00% (+100.00%) 57.14% (+57.14%) 100.00% (+100.00%)
src/components/modals/file-preview-modal.tsx 100.00% (+100.00%) 80.00% (+80.00%) 100.00% (+100.00%) 100.00% (+100.00%)
src/components/modals/image-preview-modal.tsx 100.00% (+100.00%) 75.00% (+75.00%) 100.00% (+100.00%) 87.50% (+87.50%)
src/components/modals/review-confirmation-modal.tsx 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%)
src/components/modals/submit-confirmation-modal.tsx 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%)
🚫 src/components/notices.tsx 83.33% (-2.38%) 50.00% 33.33% 83.33% (-2.38%)
🚫 src/components/openstax-feature-flag.tsx 100.00% 91.66% (-8.34%) 100.00% 95.23% (-4.77%)
src/components/page-breadcrumbs.tsx 36.84% (+36.84%) 12.50% (+12.50%) 50.00% (+50.00%) 36.84% (+36.84%)
src/components/private-key-form.tsx 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%)
🚫 src/components/readonly-lexical-content.tsx 93.33% (+1.03%) 66.66% (-8.34%) 50.00% 82.35% (-3.36%)
🚫 src/components/refresher.tsx 88.88% (-1.12%) 75.00% 100.00% 88.88% (-1.12%)
src/components/require-mfa.test.tsx 100.00% 100.00% 100.00% (+15.39%) 100.00%
src/components/require-user-key.test.tsx 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%)
src/components/require-user-key.tsx 100.00% (+100.00%) 75.00% (+75.00%) 100.00% (+100.00%) 95.23% (+95.23%)
src/components/require-user.tsx 93.33% (+0.48%) 50.00% 100.00% 93.33% (+0.48%)
src/components/required-indicator.tsx 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%)
🚫 src/components/researcher-profile/personal-info-section.tsx 100.00% 66.66% (-10.26%) 100.00% 100.00%
src/components/researcher-profile/positions-section.tsx 100.00% 100.00% 100.00% (+50.00%) 100.00%
src/components/researcher-profile/research-details-section.tsx 100.00% 100.00% (+15.79%) 100.00% (+14.29%) 100.00%
src/components/researcher-profile/researcher-profile-view.tsx 95.00% (+95.00%) 89.28% (+89.28%) 80.00% (+80.00%) 95.00% (+95.00%)
🚫 src/components/spy-mode-context.tsx 44.44% (-14.38%) 0.00% (-25.00%) 25.00% (-25.00%) 44.44% (-16.67%)
src/components/study/feedback-and-notes.test.tsx 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%)
🚫 src/components/study/feedback-and-notes.tsx 96.22% (-0.74%) 87.09% (-4.57%) 100.00% 94.82% (-2.32%)
src/components/study/file-drop-overlay.tsx 53.65% 29.41% (+2.75%) 30.76% 53.33%
🚫 src/components/study/job-approval-status.tsx 95.00% (-0.23%) 95.00% 100.00% 95.00% (-0.23%)
src/components/study/programming-language-section.test.tsx 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%)
src/components/study/programming-language-section.tsx 96.66% (+96.66%) 81.81% (+81.81%) 83.33% (+83.33%) 96.66% (+96.66%)
🚫 src/components/study/proposal-fields.tsx 100.00% 94.11% (-5.89%) 83.33% 94.73% (-5.27%)
src/components/study/proposal-step-header.tsx 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%)
src/components/study/resubmission-note-section.test.tsx 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%)
src/components/study/resubmission-note-section.tsx 94.44% (+94.44%) 91.66% (+91.66%) 100.00% (+100.00%) 95.00% (+95.00%)
src/components/study/resubmit-button.tsx 100.00% (+16.67%) 100.00% 100.00% (+100.00%) 100.00% (+16.67%)
src/components/study/review-criteria-banner.tsx 100.00% (+100.00%) 66.66% (+66.66%) 100.00% (+100.00%) 100.00% (+100.00%)
src/components/study/study-code-panel.tsx 100.00% (+5.56%) 87.50% 100.00% 100.00% (+5.27%)
🚫 src/components/study/study-code-review-view.tsx 100.00% 60.00% (-40.00%) 100.00% 100.00%
🚫 src/components/study/study-details.tsx 80.00% (-6.66%) 50.00% 50.00% 75.00% (-1.47%)
🚫 src/components/study/study-org-selector.tsx 100.00% 85.71% 100.00% 93.75% (-0.36%)
src/components/study/submitted-code-table-view.tsx 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%)
src/components/study/submitted-code-table.test.tsx 100.00% (+100.00%) 100.00% (+100.00%) 73.33% (+73.33%) 100.00% (+100.00%)
src/components/study/submitted-code-table.tsx 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%)
🚫 src/components/surety-guard.tsx 100.00% (+28.58%) 50.00% (-50.00%) 100.00% (+50.00%) 100.00% (+28.58%)
src/lib/agent-context.ts 100.00% (+100.00%) 75.00% (+75.00%) 100.00% (+100.00%) 100.00% (+100.00%)
src/lib/code-resubmission.test.ts 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%)
src/lib/code-resubmission.ts 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%)
src/lib/code-review-status.ts 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%)
🚫 src/lib/collaboration-documents.ts 100.00% 87.50% 100.00% 93.75% (-0.18%)
src/lib/config.ts 100.00% 75.00% (+25.00%) 100.00% 100.00%
src/lib/errors.ts 96.22% (+7.99%) 92.59% (+4.59%) 81.25% (+7.92%) 94.54% (+7.75%)
src/lib/file-content-helpers.ts 100.00% 95.00% (+1.25%) 100.00% 96.96% (+0.81%)
🚫 src/lib/file-type-helpers.ts 88.23% (-11.77%) 100.00% (+16.67%) 83.33% (-16.67%) 88.23% (-6.50%)
🚫 src/lib/format.ts 100.00% 50.00% (-25.00%) 100.00% 85.71%
src/lib/languages.ts 70.00% (+26.25%) 56.25% (+56.25%) 33.33% (+33.33%) 60.86% (+17.11%)
src/lib/lexical.test.ts 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%)
src/lib/lexical.ts 100.00% (+100.00%) 96.00% (+96.00%) 100.00% (+100.00%) 97.72% (+97.72%)
src/lib/logger.ts 89.47% (+10.53%) 55.00% (+15.00%) 100.00% (+12.50%) 85.36% (+9.76%)
🚫 src/lib/paths.ts 73.68% (-7.89%) 16.66% 59.25% (-3.71%) 73.68% (-7.89%)
src/lib/re-wrap-results.ts 100.00% (+100.00%) 50.00% (+50.00%) 100.00% (+100.00%) 90.90% (+90.90%)
src/lib/realtime/auth-failure.test.ts 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%)
src/lib/realtime/auth-failure.ts 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%)
src/lib/realtime/code-review-feedback-provider-context.test.tsx 100.00% (+100.00%) 100.00% (+100.00%) 83.33% (+83.33%) 100.00% (+100.00%)
src/lib/realtime/code-review-feedback-provider-context.tsx 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%)
src/lib/realtime/review-feedback-provider-context.tsx 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%)
src/lib/realtime/yjs-websocket-context.test.tsx 100.00% (+100.00%) 100.00% (+100.00%) 95.50% (+95.50%) 100.00% (+100.00%)
src/lib/realtime/yjs-websocket-context.tsx 97.43% (+97.43%) 82.05% (+82.05%) 100.00% (+100.00%) 97.64% (+97.64%)
src/lib/review-decision.ts 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%)
🚫 src/lib/routes/definitions.ts 100.00% 50.00% (-10.00%) 73.68% (+14.86%) 95.83% (-4.17%)
src/lib/routes/hooks.ts 55.55% (+5.55%) 100.00% 50.00% 55.55% (+5.55%)
🚫 src/lib/string.ts 57.37% (-4.89%) 44.44% (-5.56%) 50.00% (-7.14%) 54.16% (-5.51%)
src/lib/studies.test.ts 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%)
🚫 src/lib/studies.ts 88.88% (-11.12%) 94.73% (-5.27%) 75.00% (-25.00%) 88.88% (-11.12%)
src/lib/study-job-status.test.ts 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%)
src/lib/study-job-status.ts 100.00% (+100.00%) 80.00% (+80.00%) 88.88% (+88.88%) 100.00% (+100.00%)
src/lib/study-screen/consistency.test.ts 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%)
src/lib/study-screen/dashboard-rules.ts 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%)
src/lib/study-screen/dashboard.test.ts 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%)
src/lib/study-screen/index.ts 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%)
src/lib/study-screen/pill.test.ts 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%)
src/lib/study-screen/pill.ts 100.00% (+100.00%) 95.45% (+95.45%) 100.00% (+100.00%) 95.65% (+95.65%)
src/lib/study-screen/researcher-screen-rules.ts 100.00% (+100.00%) 100.00% (+100.00%) 88.88% (+88.88%) 100.00% (+100.00%)
src/lib/study-screen/resolve.test.ts 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%)
src/lib/study-screen/resolve.ts 100.00% (+100.00%) 75.00% (+75.00%) 100.00% (+100.00%) 100.00% (+100.00%)
src/lib/study-screen/reviewer-screen-rules.test.ts 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%)
src/lib/study-screen/reviewer-screen-rules.ts 100.00% (+100.00%) 100.00% (+100.00%) 85.71% (+85.71%) 100.00% (+100.00%)
src/lib/study-screen/screens.ts 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%)
src/lib/study-screen/state.shuffle.test.ts 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%)
src/lib/study-screen/state.test.ts 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%)
src/lib/study-screen/state.ts 100.00% (+100.00%) 96.96% (+96.96%) 100.00% (+100.00%) 100.00% (+100.00%)
src/lib/study-screen/state.types.ts 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%)
src/lib/swc-jsx-entity-whitespace.test.ts 91.30% (+91.30%) 0.00% 100.00% (+100.00%) 91.66% (+91.66%)
🚫 src/lib/types.ts 95.34% (+0.34%) 60.00% (-6.66%) 90.90% (+0.90%) 95.34% (+0.34%)
🚫 src/server/actions/action.ts 91.46% (-0.10%) 64.86% 90.90% 91.76% (-0.10%)
src/server/actions/agent-context.actions.test.ts 100.00% (+100.00%) 50.00% (+50.00%) 100.00% (+100.00%) 100.00% (+100.00%)
src/server/actions/agent-context.actions.ts 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%)
src/server/actions/editor.actions.ts 100.00% (+33.34%) 66.66% (+16.66%) 100.00% (+50.00%) 100.00% (+33.34%)
src/server/actions/org.actions.test.ts 98.29% (+0.05%) 100.00% 100.00% 98.29% (+0.05%)
🚫 src/server/actions/org.actions.ts 75.55% 0.00% 60.00% (-2.50%) 75.55%
src/server/actions/researcher-profile.actions.ts 86.36% (+0.32%) 87.50% 82.35% 86.95% (+0.29%)
src/server/actions/resubmit-proposal.test.ts 100.00% (+100.00%) 50.00% (+50.00%) 100.00% (+100.00%) 100.00% (+100.00%)
src/server/actions/study-job.actions.test.ts 100.00% 100.00% 94.73% (+1.88%) 100.00%
🚫 src/server/actions/study-job.actions.ts 79.51% (-14.49%) 69.56% (+36.23%) 73.33% (-12.38%) 76.13% (-16.02%)
🚫 src/server/actions/study-request.ts 96.69% (+3.84%) 72.22% (-4.70%) 93.44% (+10.59%) 95.18% (+2.19%)
🚫 src/server/actions/study.actions.test.ts 100.00% 80.00% (-20.00%) 99.24% (-0.76%) 100.00%
🚫 src/server/actions/study.actions.ts 94.66% (+6.51%) 81.18% (-3.30%) 100.00% (+13.52%) 94.34% (+6.03%)
src/server/actions/user-keys.actions.ts 94.11% (+8.40%) 100.00% (+50.00%) 62.50% (+12.50%) 94.11% (+8.40%)
🚫 src/server/actions/user.actions.ts 76.31% (+0.64%) 62.50% 87.50% (-1.38%) 76.31% (+0.64%)
src/server/actions/workspace-files.actions.ts 37.83% (+10.06%) 0.00% 57.14% (+57.14%) 37.83% (+10.06%)
src/server/actions/workspaces.actions.test.ts 98.98% (+1.26%) 50.00% 100.00% 98.98% (+1.26%)
src/server/actions/workspaces.actions.ts 80.00% (+1.54%) 64.44% (+8.03%) 72.22% (+3.47%) 74.68% (+3.06%)
src/server/agents/review-agent/agent.test.ts 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%)
src/server/agents/review-agent/agent.ts 97.05% (+97.05%) 87.50% (+87.50%) 100.00% (+100.00%) 97.14% (+97.14%)
src/server/agents/review-agent/prompts.ts 100.00% (+100.00%) 75.00% (+75.00%) 100.00% (+100.00%) 100.00% (+100.00%)
src/server/agents/review-agent/runner.test.ts 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%)
src/server/agents/review-agent/runner.ts 93.44% (+93.44%) 85.00% (+85.00%) 100.00% (+100.00%) 93.65% (+93.65%)
src/server/agents/review-agent/types.ts 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%)
🚫 src/server/aws.test.ts 98.63% (-0.22%) 50.00% 100.00% 98.63% (-0.22%)
🚫 src/server/aws.ts 36.23% (-2.98%) 26.72% (-1.72%) 52.38% (-1.46%) 33.33% (-2.67%)
🚫 src/server/coder/client.ts 100.00% 92.30% (-7.70%) 100.00% 100.00%
🚫 src/server/coder/workspaces.ts 39.66% (-30.61%) 22.97% (-7.93%) 33.33% (-16.67%) 39.01% (-30.01%)
🚫 src/server/coder.test.ts 99.04% (+0.08%) 90.32% (-4.84%) 100.00% 98.14% (-0.86%)
src/server/config.ts 90.00% (+0.26%) 72.50% 75.00% 91.30% (+0.19%)
src/server/db/mutations.test.ts 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%)
src/server/db/mutations.ts 100.00% (+62.50%) 94.73% (+23.31%) 100.00% (+75.00%) 100.00% (+64.71%)
🚫 src/server/db/queries.test.ts 100.00% 50.00% (-50.00%) 100.00% 99.06% (-0.94%)
src/server/db/queries.ts 84.25% (+9.59%) 36.66% (+20.00%) 89.36% (+15.17%) 82.88% (+10.16%)
src/server/db/study-state-query.test.ts 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%)
src/server/db/study-state-query.ts 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%)
src/server/dev.test.ts 100.00% (+100.00%) 50.00% (+50.00%) 100.00% (+100.00%) 97.14% (+97.14%)
src/server/dev.ts 85.29% (+64.46%) 60.00% (+26.67%) 75.00% (+25.00%) 81.57% (+58.50%)
src/server/events.test.ts 100.00% (+100.00%) 100.00% (+100.00%) 92.85% (+92.85%) 100.00% (+100.00%)
src/server/events.ts 86.84% (+4.76%) 100.00% 68.18% (+6.28%) 86.84% (+4.76%)
src/server/mutations.ts 75.00% (+18.75%) 40.00% (+10.00%) 66.66% 75.00% (+18.75%)
src/server/results-sharing.test.ts 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%)
src/server/results-sharing.ts 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%)
src/server/s3-integration.test.ts 100.00% 75.00% 100.00% 98.96% (+0.01%)
src/server/storage.ts 76.92% (+8.92%) 100.00% 62.50% (+12.50%) 76.92% (+8.92%)
src/server/user-sync.test.ts 99.05% (+0.09%) 100.00% 95.65% (+0.42%) 99.05% (+0.09%)
src/server/user-sync.ts 90.32% (+6.45%) 93.75% (+12.50%) 100.00% 90.32% (+6.45%)
src/server/utils.test.ts 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%) 100.00% (+100.00%)
src/server/utils.ts 100.00% (+100.00%) 87.50% (+87.50%) 100.00% (+100.00%) 100.00% (+100.00%)

@chrisbendel chrisbendel merged commit a890ba3 into main Jun 25, 2026
8 of 9 checks passed
@chrisbendel chrisbendel deleted the researcher-encrypted-results branch June 25, 2026 19:47
@github-actions github-actions Bot locked and limited conversation to collaborators Jun 25, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants