Repository navigation
feat(client): reach-out guide page linked from detail pages (draft for #5167) - #5156
Merged
Merged
Conversation
The /research hero now names labs, centers, and faculty research in every field instead of labs alone. Detail pages drop internal labels: Sources chips use student wording for access signals and the lead contribution, the lead-under-review notice reads plainly, grant funders are spelled out, and the topic chips are headed "Topics". A principal investigator heading gains a one-line explanation. A new generic /getting-started guide answers whether first-years can join, what a PI is, and how to write a first email, pointing to Yale College's own advice. Every How to get involved block links to it, including a minimal block where the lead card is the only way in. A served join route whose address is not a join page is labelled for what it is. Closes #5099
There was a problem hiding this comment.
Approved automatically: the author holds the Admin repository role (#4512).
quntao-z
marked this pull request as draft
October 18, 2026 19:09
…a's copy fixes and re-apply the reach-out guide
# Conflicts: # client/src/pages/labDetail.tsx
quntao-z
marked this pull request as ready for review
October 20, 2026 16:44
There was a problem hiding this comment.
Approved automatically: the author holds the Admin repository role (#4512).
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.
Draft, held for design review in #5167. Per the owner rule, the reach-out guide is a design-first feature: this PR is the reference implementation for that design and is not to be merged until #5167 is approved. The bug-fix half of #5099 (jargon, hero copy, join-label honesty) lands separately.
Intent
Make y/labs student-facing copy speak the student's language and give newcomers one generic, accurate guide to reaching out (issue #5099). The /research hero should invite every field, not only labs. Detail pages should stop showing internal labels (lead contribution chip, title-cased access-signal enums, "opened above", "Lead identity under review", bare funder acronyms, "Best fit for" over topics) and should explain what a principal investigator is. A new /getting-started page answers can first-years join, what a PI is, and how to write the first email, linked from every How to get involved block, including a minimal block where the lead card is the only way in. A served join route whose address is not a join page must not be labelled as one. Serve-time client copy only: no stored data, no per-entity generated text. PR body rule: describe the regression tests by behaviour only and never quote a test fixture string, slug, or name from the diff, because the guard scans the body and a quoted fixture reads as a real person.
What Changed
/getting-startedpage that covers whether first-years can join, what a PI is, how to write a first email, pay and credit, and other ways in. It has its own page-shell title.ScrollToTopnow lets a#sectionhash on a route change scroll to that section instead of jumping to the top. Every "How to get involved" block links to the guide. That includes a new minimal block shown when the lead card is the only way in. Principal Investigator headings now carry a one-line explanation that links to the guide's PI section./researchhero now invites labs, centers, and faculty research in every field.Refs #5099, #5167
Risk Assessment
✅ Low: The fix round correctly resolves all four round-1 findings with narrow, well-tested changes: ScrollToTop skips the top reset when the hash names a committed element, the malformed hash is caught, roster tokens are dropped from JOIN_SHAPED_PATH, and the vacuous assertion now queries the renamed chip.
Testing
The Test agent exceeded its invocation budget before live validation completed; no evidence was gathered for this head.
Pipeline
Updates from git push no-mistakes
✅ **intent** - passed
✅ No issues found.
✅ **Rebase** - passed
✅ No issues found.
🔧 **Review** - 4 issues found → auto-fixed ✅
client/src/pages/gettingStarted.tsx:42- The 'What a PI does' link may not land on the PI section. Clicking it from a detail page is an in-app PUSH to/getting-started#what-is-a-pi, which counts as a route change. The globalScrollToTop(client/src/components/shared/ScrollToTop.tsx) then sets targetScrollTop=0. Its first requestAnimationFrame callback callsapplyTargetScrollTop()unconditionally, and that frame runs after this page's passive effect has calledscrollIntoView. So once the lazy chunk is already loaded (any visit after the first), the section scroll is reset to the top. Focus still moves to the heading while the view stays at the top of the page. The new test rendersMemoryRouterwithoutScrollToTop, so it never exercises this. Fix at the shared boundary: haveScrollToTopskip the scroll-to-top target whenlocation.hashnames an element, rather than adding a retry in the page.client/src/pages/__tests__/labDetail.test.tsx:1448-expect(screen.queryByText('opened above')).toBeNull()now always passes, because labDetail.tsx:850 renames that chip to 'also linked above'. The regression test ('does not mark an official profile opened above when a join page takes the only action') no longer guards anything. Change the assertion to query 'also linked above'.client/src/utils/researchDetailSources.ts:548-JOIN_SHAPED_PATHis a second, wider copy of the existingAPPLY_OR_JOIN_PATH(line 495). It adds tokens such asstudents?,undergrad(?:uate)?s?,careers?,jobs?,positions?andapply. A vetted APPLICATION_FORM_EXISTS route on a member-roster page likehttps://lab.example.test/studentsor/members/undergraduates(not under a profile-like prefix) therefore still gets the 'See how to join' label. The intent requires that 'A served join route whose address is not a join page must not be labelled as one', and a roster page is not a join page. Narrower option: extendAPPLY_OR_JOIN_PATHwith only the invitation-shaped tokens (opportunities, openings, positions, prospective) and drop the roster-shapedstudents/undergradtokens, so one join-path definition remains. Whether staff-job tokens (careers,jobs) count as join pages is a product call.client/src/pages/gettingStarted.tsx:37-decodeURIComponent(hash...)throws URIError on a malformed escape such as/getting-started#%E0. The error is thrown inside an effect and reaches the error boundary, so a mistyped or shared link crashes the guide page. Wrap the decode in try/catch and return early on failure, asdecodePathSegmentdoes on the server.🔧 Fix applied.
✅ Re-checked - no issues remain.
✅ **Document** - passed
✅ No issues found.
✅ **Lint** - passed
✅ No issues found.
✅ **Push** - passed
✅ No issues found.