Redesign livepeer.org - #93
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
In-progress rows now carry the day the update was posted, as shipped rows carry theirs. Owner and date are set in the foreground and the update in the muted voice, so the break in colour is the boundary between the record and the words. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
There was a problem hiding this comment.
🔵 Needs a closer look
The change set is very large and includes new routes/security-sensitive behaviors; it needs final human review even though only a few specific issues were identified here.
Review details
Suppressed comments (2)
app/changelog/roundup.json/route.ts:54
roundup.jsondefaults to the current (in-progress) month, but/changelog/<month>intentionally 404s for the current month. As written, theurlfield will therefore point consumers at a 404 for the default case; consider pointing to the index whenr.currentis true.
app/api/revalidate/route.ts:44- This endpoint compares the bearer token with a normal string equality check. Using a timing-safe comparison avoids leaking information via response timing and is a common hardening for shared-secret auth.
- Files reviewed: 127/338 changed files
- Comments generated: 0 new
- Review effort level: Lite
Owner and date keep theirs; the words follow after a wider gap in the muted voice. A third middot gave them the weight of a third field. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
There was a problem hiding this comment.
🔵 Needs a closer look
The ecosystem project OG image route currently renders the same non-titled card for every project (contradicting the stated behavior) and the revalidation endpoint should use constant-time token comparison for a safer auth gate.
Review details
Suppressed comments (2)
app/ecosystem/[slug]/opengraph-image.tsx:16
- This dynamic OG image is identical for every ecosystem project (it ignores
params.slugand rendersrenderArtCard(ogArt.ecosystem)), which contradicts the PR description that project pages get their own titled card and makes all shares from /ecosystem/ indistinguishable.
app/api/revalidate/route.ts:46 - Bearer token validation uses a direct string comparison (
offered !== secret). For an authentication gate, prefer a constant-time comparison to reduce exposure to timing attacks (even if low-risk over the network).
- Files reviewed: 127/338 changed files
- Comments generated: 0 new
- Review effort level: Lite
There was a problem hiding this comment.
🔵 Needs a closer look
Several new UI primitive modules are missing an explicit "use client" directive despite being imported by client components and/or using hooks, which can break Next.js App Router client/server boundary rules.
Review details
- Files reviewed: 127/338 changed files
- Comments generated: 0 new
- Review effort level: Lite
A month's entry is a record and does not change, but a reader who saw "At risk" in August and opened a record that said On track felt the site contradict itself. A row now carries the story since the month closed, after its own word and only where it differs — "now on track", "now shipped", "now no update" — so the record stays what it was and the click through is not a surprise. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This reverts commit 56a7812.
There was a problem hiding this comment.
🔵 Needs a closer look
The updated GitHub Actions workflow references non-existent action majors (actions/checkout@v7 and actions/setup-node@v7), which will break CI execution.
Review details
- Files reviewed: 127/338 changed files
- Comments generated: 0 new
- Review effort level: Lite
There was a problem hiding this comment.
🔵 Needs a closer look
The PR is a large, cross-cutting redesign with new ISR/revalidation and content pipeline behavior, and it includes at least two concrete correctness issues to address before merge.
Review details
Suppressed comments (2)
app/api/revalidate/route.ts:50
revalidatePath(PATH)only invalidates the exact/roadmaproute; it won’t reliably refresh nested pages like/roadmap/[slug]that also depend on the Notion register. Use the"layout"scope so an agent-triggered revalidation actually updates the whole roadmap segment.
app/changelog/roundup.json/route.ts:54- This endpoint defaults to returning the month currently under way, but
/changelog/<current-month>is intentionally not published (it 404s until the month ends). Returning a URL that is expected to 404 makes the JSON harder to consume; consider pointingurlat/changelogwhencurrentis true.
- Files reviewed: 127/338 changed files
- Comments generated: 0 new
- Review effort level: Lite
The register cut by the body answerable for each commitment: every owner as a heading linking to its page, its commitments beneath with what needs attention first — off track, at risk, silent, on track, then committed work with no health yet by target — and the bodies ordered by the worst thing under them, so the page opens on whoever has something to answer for. In the URL as ?group=owner, so it is a link you can send. Roadmap only; Shipped keeps its months. The control sits at the far end of the view tabs from lg up and inside the Filters panel below that, where a second line in the tab row would have slid the sticky bands under it. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Shipped by owner is a track record per body, most recent first. The "Nothing is committed past …" line answers when, so it shows under the quarter cut and not the owner cut, which is answering who. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
There was a problem hiding this comment.
🔵 Needs a closer look
It’s a large, cross-cutting redesign (routing, metadata/sharing, content sources, and new endpoints), so it needs careful human validation beyond the specific issues flagged.
Review details
Suppressed comments (2)
app/ecosystem/submit/page.tsx:51
fs.readFileSyncruns during render, so this page will re-readcontent/ecosystem-template.mdevery time it’s requested (or every time the server component is evaluated). Since the template is static, cache the computed GitHub “new file” URL at module scope (or behind a simple in-module memo) to avoid repeated synchronous I/O.
app/people/[slug]/opengraph-image.tsx:22- This people share-card is rendered with
ogArt.organizations, which means people pages will share the Organizations background art (and any future changes intended for org pages will also affect people). If this is accidental (copy/paste from the org route), consider adding a dedicatedogArt.peopleentry inlib/og.tsx(or selecting an existing non-org art constant) and using it here.
- Files reviewed: 127/338 changed files
- Comments generated: 0 new
- Review effort level: Lite
There was a problem hiding this comment.
🔵 Needs a closer look
The change set is a full-site redesign with many new routes/components and content model changes, so it warrants final human validation despite only a couple of concrete issues found in the reviewed hunks.
Review details
Suppressed comments (1)
app/people/[slug]/opengraph-image.tsx:22
- This person card uses
ogArt.organizations, which will make every /people/ share image look like an organization page. There isn’t a dedicated people art token inlib/og.tsx; using the roadmap art is a closer match for people being a roadmap-adjacent surface.
- Files reviewed: 127/338 changed files
- Comments generated: 0 new
- Review effort level: Lite
The four words of the scale with their counts, always all four — Off track 0 is news — read as a filter the way Linear filters projects by health. It doubles as the tally the accountability board kept in its footer, and puts the silent ones one click away. Roadmap only, in the URL as ?health=, dropped on the way to Shipped like the state flag. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
There was a problem hiding this comment.
🔵 Needs a closer look
The change set is a broad redesign touching routing, UI primitives, and dynamic data/metadata surfaces, and it includes at least one correctness issue that should be fixed and then re-verified end-to-end.
Review details
Suppressed comments (1)
app/ecosystem/[slug]/opengraph-image.tsx:17
- This OG image implementation renders the same generic
renderArtCard(ogArt.ecosystem)for every project. That contradicts the PR description (“All 12 projects now get their own titled card”) and makes different ecosystem project links indistinguishable in timelines.
Use renderTitledCard(...) and the project’s name (from the slug) so each project gets a unique share image.
- Files reviewed: 127/338 changed files
- Comments generated: 0 new
- Review effort level: Lite
A route and a tick for the two views, a calendar and a building for the two cuts, the way Linear marks its filters. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
There was a problem hiding this comment.
🔵 Needs a closer look
The change set is a broad site redesign spanning routing, content sourcing, build/runtime behavior, and security-sensitive endpoints, which warrants focused human validation beyond automated review.
Review details
Suppressed comments (2)
app/api/revalidate/route.ts:2
- The token check should use a constant-time comparison;
timingSafeEqual(node:crypto) is a straightforward way to do that, but it needs to be imported.
app/api/revalidate/route.ts:47 - Bearer token validation uses a plain string comparison (
offered !== secret), which can leak information via timing differences. Compare in constant time (and check equal length) before allowing revalidation.
- Files reviewed: 127/338 changed files
- Comments generated: 1
- Review effort level: Lite
| <a | ||
| key={item.label} | ||
| href={item.href} | ||
| target="_blank" | ||
| rel="noreferrer" | ||
| onClick={close} | ||
| className={className} | ||
| > |
There was a problem hiding this comment.
🟡 Changes recommended
There are user-visible regressions/discrepancies in the ecosystem surface (share cards not titled per project and loss of URL-deep-linking for filters/search) that should be resolved before approval.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review details
Suppressed comments (1)
app/ecosystem/[slug]/opengraph-image.tsx:17
- This OpenGraph image generator returns renderArtCard(ogArt.ecosystem), so every ecosystem project page gets the same lockup-only card with no project title. The PR description states each project should get its own titled card; as written, shared links won’t be distinguishable in a timeline.
- Files reviewed: 127/338 changed files
- Comments generated: 1
- Review effort level: Lite
| export default function EcosystemPage() { | ||
| const apps: EcosystemListingApp[] = getAllApps().map((app) => ({ | ||
| slug: app.slug, | ||
| name: app.name, | ||
| url: app.url, | ||
| hostname: app.hostname, | ||
| displayUrl: app.displayUrl, | ||
| description: app.description, | ||
| categories: app.categories, | ||
| logo: app.logo, | ||
| logoBg: app.logoBg, | ||
| logoMonochrome: app.logoMonochrome, | ||
| })); | ||
| const categories = getEcosystemCategories(); | ||
|
|
||
| return ( | ||
| <EcosystemListingClient | ||
| <EcosystemListing | ||
| apps={apps} | ||
| categories={categories} | ||
| initialCategories={ | ||
| catsParam ? catsParam.split(",").map(decodeURIComponent) : [] | ||
| } | ||
| initialSearch={q ?? ""} | ||
| categories={getEcosystemCategories()} | ||
| heading={ecosystem.heading} | ||
| searchPlaceholder={ecosystem.searchPlaceholder} | ||
| emptyMessage={ecosystem.emptyMessage} | ||
| submitLabel={ecosystem.submitLabel} | ||
| submitHref={ecosystem.submitHref} | ||
| /> |
A post on a commitment now has a kind: the monthly update while the work is under way, or the one retrospective once it has shipped. Marked in Notion with a Kind select rather than inferred from its date, because a retro is often written the day something ships and an "it's out" update lands after; a retrospective carries no health, since "on track" means nothing about something finished. - Shipped cards read "Retro done" or "No retro" after the state. - A shipped record leads with its retrospective, or with the fact that none has been written, and the activity log runs in date order so the retro sits where it happened rather than under a pinned "shipped it". - The changelog's shipped rows carry the retro's line where one existed by the month's end, and roundup.json lists the month's shipped work without a retro as noRetro beside the silent. - Both readers accept the kind; the fallback gains a seed retro. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The tick disc and "Retrospective" where one exists, a hollow ring and "No retrospective" in the foreground where not. Not a checkbox, which on a card looks clickable; this is a fact. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
There was a problem hiding this comment.
🔵 Needs a closer look
The PR is a large WIP site redesign touching many routes, content sources, and metadata/share-image behaviors, so it needs targeted manual validation of key user flows and deploy/runtime behavior beyond automated review.
Review details
Suppressed comments (3)
app/ecosystem/[slug]/opengraph-image.tsx:17
- This project share-image route renders an art-only card (renderArtCard), but the PR description says ecosystem project pages now get a titled card. As written, the OG image will not include the project name, so shared links are harder to distinguish in a feed.
app/api/revalidate/route.ts:46 - The bearer token check uses a direct string comparison (
offered !== secret). For secret validation endpoints, a constant-time compare is safer to avoid leaking information via timing differences.
app/changelog/roundup.json/route.ts:54 - The JSON payload always advertises
url: https://livepeer.org/changelog/<month>, butroundup.jsondefaults to the current month (r.current=true) and the changelog month pages intentionally do not publish the current month. For the default case, this URL will point at a 404.
- Files reviewed: 127/339 changed files
- Comments generated: 0 new
- Review effort level: Lite
In medium weight above the muted write-up, in the log and on the card, so it reads as the lead rather than a paragraph that forgot its colour. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The row's header has already said who, what and when, and a second title fought the write-up's bold lead-ins. The card keeps the title treatment, having no header row to lean on. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Weight alone left it level with the write-up's bold lead-ins; at the body's size it was a paragraph in a different colour. One step up, in the log and on the card. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
There was a problem hiding this comment.
🔵 Needs a closer look
Several routes hard-disable dynamic params for Notion-backed records (risking permanent 404s for newly added rows) and there is at least one inconsistent shipped date that can misgroup changelog output.
Review details
Suppressed comments (3)
Previously missed (3) — in code that hasn't changed since the last review.
app/organizations/[slug]/page.tsx:25
dynamicParams = falseprevents organization pages for new org rows added in Notion after the last build, even if the roadmap starts crediting/owning work under that org. Leaving dynamic params enabled keeps unknown slugs 404ing vianotFound()while allowing new orgs to be served on first request.
app/people/[slug]/page.tsx:19- With
dynamicParams = false, any new person added in Notion after the last build will 404 permanently (until a rebuild), even if commitments start linking to them. Consider leaving dynamic params enabled and relying onnotFound()for unknown slugs so the People table can grow without a deploy.
app/roadmap/[slug]/page.tsx:32 dynamicParams = falsemeans any new commitment added in Notion after the last build can appear on /roadmap but its detail page will still 404 because it wasn’t ingenerateStaticParams()at build time. Leaving dynamic params enabled allows new slugs to be served on first request while still 404ing unknown slugs vianotFound().
- Files reviewed: 127/339 changed files
- Comments generated: 0 new
- Review effort level: Lite
The expanded body started on the header's line and the title's leading was tight. More above the title, a looser line, a beat more below. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
There was a problem hiding this comment.
🔵 Needs a closer look
There’s at least one confirmed functional issue (checkbox ::after never renders without content) plus a verified mismatch between the PR description and the ecosystem project OG card behavior (art-only vs titled card).
Review details
Suppressed comments (1)
app/ecosystem/[slug]/opengraph-image.tsx:17
- The PR description says ecosystem project pages now get “their own titled card”, but this opengraph image currently renders the generic art-only card (no project title). Either update the description or render a titled card using the project’s name (similar to blog post cards).
- Files reviewed: 127/339 changed files
- Comments generated: 0 new
- Review effort level: Lite
There was a problem hiding this comment.
🔵 Needs a closer look
This is a wide-ranging site redesign touching many routes/content systems, and there are unresolved review findings (security + UI class issue) that should be addressed alongside final human verification.
Review details
Suppressed comments (1)
app/api/revalidate/route.ts:46
- The bearer token check uses a direct string comparison (
offered !== secret), which is vulnerable to timing attacks. For a shared-secret auth check, use a constant-time comparison to avoid leaking information about the secret via response timing.
- Files reviewed: 127/339 changed files
- Comments generated: 0 new
- Review effort level: Lite
Rebuilds the marketing site against Peace Node's Livepeer UI registry. The registry theme is now the only token layer.
Pages
Nine linked pages, all built from the mockup set except where noted:
//agent/ecosystem/[slug],/submit— markdown-driven catalog/compute/token/foundation/blog/blog/brand/roadmap/primerstays intact and unlinked with its own scoped legacy slice — the one page deliberately left unmigrated.Content is split on its shape and how often it changes. Page copy is authored in-repo as typed objects matching the registry's content contracts (
lib/site.ts) — versioned and reviewed alongside the design it belongs to. Blog and ecosystem are markdown incontent/.Templated content that gets updated frequently moves to Notion, and the roadmap register is the first of it. It is maintained by people across several organisations who do not open pull requests, and a commitment whose state is a week stale is worse than no page at all. The blog is planned next; scope is those two for now, not a general move of the site into a CMS. So this PR is the pattern as much as the page.
lib/notion.tsreads it over plainfetchwith ISR at a minute;content/roadmap/*.mdis the fallback when no workspace token is present, so a clone still builds. Every record carries an owner, a target and a checkable link, and anything missing one fails the build rather than rendering a card that claims less than it should.Cleanup
globals.css1209 → 585 lines. Removed the second--color-*token layer, the Holographik grid, hero classes,.blog-prose, 19 keyframes and 37 custom properties. Chart/sidebar/radius tokens are kept — unused today, but they're the registry's theme contract.Deleted ~73 files:
components/home/*,components/legacy/*,components/ecosystem/*(superseded bycomponents/livepeer-ui/*), the PascalCasecomponents/ui/*visuals,lib/constants.ts, and the fiveapp/use-cases/*routes — redirects innext.config.tsalready served those URLs, so the pages were unreachable.Share images
Rebuilt on the registry's own
ogitem./renders the brand card verbatim — the lockup centred on#000000. Every other page renders the same canvas with a page title, from one sharedlib/og.tsx. Two bugs fixed along the way:twitter-image, and metadata files cascade — so/foundationand/blogserved their ownog:imagebut the root's Twitter card. Every segment now has a re-export beside itsopengraph-image.generateMetadatadeclares anopenGraphobject withoutimages, which drops the inherited card. All 12 projects now get their own titled card.Incidental fixes
app/not-found.tsxstyled its linktext-green— green as an affordance colour, which the design system explicitly rules out. Rebuilt on the registry type scale.sitemap.tsadvertised the five dead/use-casesURLs and never listed/agentor/compute. Rewritten, with ecosystem projects added.package-lock.jsondeleted. Six deps had been added vianpmin a pnpm-pinned repo, leavingpnpm-lock.yamlstale —pnpm install --frozen-lockfilewas failing, which would have broken the Vercel build. Lockfile regenerated and verified.Verification
pnpm typecheck,pnpm lint(0 warnings) andpnpm build(130 static pages) all clean, against both the Notion register and the markdown fallback. Pages verified in light and dark at 390px, sm, md and wide desktop.Before this can ship
agentAppOriginis the console's Vercel preview (lib/site.ts) —livepeer-console.vercel.app, not its final address. It feeds the most prominent CTA on every page, so it still needs one edit before launch. The Agent playbooks link is the one product link left onlivepeer.peaceno.de: the console has no playbooks page, and a mockup beats a 404.forum.livepeer.org/or similar rather than a permalink.🤖 Generated with Claude Code