diff --git a/apps/website/next-env.d.ts b/apps/website/next-env.d.ts
index fdbfe5258..c4b7818fb 100644
--- a/apps/website/next-env.d.ts
+++ b/apps/website/next-env.d.ts
@@ -1,6 +1,6 @@
///
///
-import "./../../dist/apps/website/.next/types/routes.d.ts";
+import "./.next/dev/types/routes.d.ts";
// NOTE: This file should not be edited
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
diff --git a/apps/website/src/app/about/page.spec.tsx b/apps/website/src/app/about/page.spec.tsx
index ffa3d47ed..6e4b41964 100644
--- a/apps/website/src/app/about/page.spec.tsx
+++ b/apps/website/src/app/about/page.spec.tsx
@@ -5,6 +5,7 @@ import { describe, expect, it, vi } from 'vitest';
import { render, screen } from '@testing-library/react';
import AboutPage from './page';
import { getAuthor } from '../../lib/blog-authors';
+import { ABOUT_PARAGRAPHS } from '../../lib/about-content';
vi.mock('../../components/ui/Container', () => ({
Container: ({ children }: { children: React.ReactNode }) =>
{children}
,
@@ -24,17 +25,36 @@ const author = getAuthor('brian');
* claims back to the author record rather than restating the layout.
*/
describe('AboutPage', () => {
- it('renders the bio verbatim from the author record', () => {
+ it('renders each sourced paragraph verbatim', () => {
render();
- // Not a substring match: any editorial embellishment around the sourced
- // sentence would still be a claim nothing in the repo supports.
- expect(screen.getByText(author.bio as string).textContent).toBe(author.bio);
+ // Not substring matches: editorial embellishment around a sourced sentence
+ // would still be a claim nothing citable supports.
+ for (const paragraph of ABOUT_PARAGRAPHS) {
+ expect(screen.getByText(paragraph).textContent).toBe(paragraph);
+ }
});
- it('states the name and role the author record gives, and no other', () => {
+ it('adds no biographical prose beyond the sourced paragraphs', () => {
+ // The real guard. Every claim on this page has to trace to about-content.ts,
+ // whose provenance comment names the source; a paragraph appearing here that
+ // is not in that module is exactly the fabrication this page must not carry.
+ const { container } = render();
+ const sourced = new Set(ABOUT_PARAGRAPHS);
+
+ const biography = container.querySelectorAll('section')[0];
+ const paragraphs = Array.from(biography.querySelectorAll('p'))
+ .map((node) => node.textContent ?? '')
+ .filter((text) => text.split(' ').length > 12);
+
+ expect(paragraphs.length).toBe(ABOUT_PARAGRAPHS.length);
+ for (const text of paragraphs) {
+ expect(sourced.has(text), text).toBe(true);
+ }
+ });
+
+ it('names the author the record gives', () => {
render();
- expect(screen.getByText(`Threadplane is written and maintained by ${author.name}, ${author.role}.`))
- .toBeTruthy();
+ expect(screen.getByText(ABOUT_PARAGRAPHS[0]).textContent).toContain(author.name);
});
it('links the GitHub profile the record names', () => {
diff --git a/apps/website/src/app/about/page.tsx b/apps/website/src/app/about/page.tsx
index 696662841..0f63937a9 100644
--- a/apps/website/src/app/about/page.tsx
+++ b/apps/website/src/app/about/page.tsx
@@ -9,6 +9,13 @@ import { aboutPageJsonLd, REPOSITORY_URL } from '../../lib/structured-data';
import { getAuthor } from '../../lib/blog-authors';
import { createPageMetadata } from '../../lib/site-metadata';
import { LONG_SUBHEAD } from '../../lib/positioning';
+import {
+ ABOUT_HISTORY,
+ ABOUT_HISTORY_HEADING,
+ ABOUT_INTRO,
+ ABOUT_PERSONAL,
+ ABOUT_PRINCIPLES,
+} from '../../lib/about-content';
/**
* The single author record the site already publishes (blog bylines read the
@@ -68,10 +75,18 @@ export default function AboutPage() {
>
Who writes Threadplane
-
- Threadplane is written and maintained by {author.name}, {author.role}.
-
- {author.bio}
+ {ABOUT_INTRO}
+
+ {ABOUT_HISTORY_HEADING}
+ {ABOUT_HISTORY.map((paragraph) => (
+
+ {paragraph}
+
+ ))}
+
+ {ABOUT_PRINCIPLES}
+ {ABOUT_PERSONAL}
+
= {
brian: {
name: 'Brian Love',
role: 'Founder, Threadplane',
- bio: 'Angular consultant and open-source maintainer. Building agent UI for Angular teams.',
+ bio: 'Agentic software architect building developer tooling for fullstack AI-powered web applications.',
knowsAbout: ['Angular', 'TypeScript', 'LangGraph', 'AG-UI', 'Generative UI', 'Agent user interfaces'],
github: 'blove',
},