165 lines
6.5 KiB
TypeScript
165 lines
6.5 KiB
TypeScript
import type { Metadata } from "next";
|
|
import {
|
|
ButtonLink,
|
|
Container,
|
|
SectionHeader,
|
|
TerminalCard,
|
|
} from "@/src/components/site";
|
|
import { ProcessStepCard } from "@/src/components/process/ProcessStepCard";
|
|
import { PROCESS_STEPS } from "@/src/components/process/processSteps";
|
|
import { SAMPLE_DELIVERY_REPORT } from "@/src/components/process/sampleDeliveryReport";
|
|
import { formatDeliveryReport } from "@/src/domain/deliveryReport";
|
|
|
|
const TITLE = "Process: AI speed, engineering proof";
|
|
const DESCRIPTION =
|
|
"How I ship AI-accelerated code that holds up: spec first, red, green, mutation check and a delivery report with exact commands and results on every pull request.";
|
|
|
|
export const metadata: Metadata = {
|
|
title: TITLE,
|
|
description: DESCRIPTION,
|
|
alternates: { canonical: "/process" },
|
|
openGraph: {
|
|
title: TITLE,
|
|
description: DESCRIPTION,
|
|
url: "/process",
|
|
type: "website",
|
|
},
|
|
};
|
|
|
|
const GUARDRAILS = [
|
|
{
|
|
title: "Pre-commit gate",
|
|
text: "Formatting and lint on staged files, then typecheck and the unit tests, run before a commit is created. Broken code does not enter history.",
|
|
},
|
|
{
|
|
title: "Pre-push gate",
|
|
text: "Coverage runs before a push leaves my machine, and the mutation check runs when the domain logic changed. The remote only receives green work.",
|
|
},
|
|
{
|
|
title: "CI gates the deploy",
|
|
text: "On client projects the same checks run again in CI, and a deploy only starts when they pass. My machine is not the only line of defense.",
|
|
},
|
|
{
|
|
title: "Tests are never weakened",
|
|
text: "If a test blocks a change, I do not skip, loosen or delete it to get green. If the test is wrong, I tell you why and the spec changes with your agreement.",
|
|
},
|
|
] as const;
|
|
|
|
const reportLines = formatDeliveryReport(SAMPLE_DELIVERY_REPORT);
|
|
|
|
export default function Page() {
|
|
return (
|
|
<Container className="py-16 md:py-24">
|
|
<SectionHeader
|
|
as="h1"
|
|
kicker="/process"
|
|
title="How I ship AI-accelerated code that holds up"
|
|
lead="AI makes code cheap to produce. What you pay for is code that is correct. Every change goes through the same five steps, and you get the evidence for each of them every week."
|
|
/>
|
|
|
|
<section aria-labelledby="steps" className="mt-16">
|
|
<h2 id="steps" className="sr-only">
|
|
The five steps
|
|
</h2>
|
|
<p className="!mb-6 max-w-2xl text-base text-muted">
|
|
One running example: parsing an availability, meaning a date and
|
|
weekly hours. The date 2026-02-30 must be rejected, 2028-02-29 must be
|
|
accepted, and 168 hours is the upper boundary of a week.
|
|
</p>
|
|
<ol className="list-none !p-0">
|
|
{PROCESS_STEPS.map((step, index) => (
|
|
<ProcessStepCard key={step.id} step={step} index={index} />
|
|
))}
|
|
</ol>
|
|
</section>
|
|
|
|
<section aria-labelledby="report" className="mt-16">
|
|
<SectionHeader
|
|
kicker="evidence"
|
|
title="A delivery report"
|
|
lead="This is what arrives with a pull request. The example below is illustrative: the numbers are made up for the availability parsing case and are not from a client project."
|
|
/>
|
|
<TerminalCard
|
|
title="delivery report (illustrative example)"
|
|
className="mt-8 max-w-3xl"
|
|
>
|
|
{reportLines.map((line) => (
|
|
<p key={line} className="!mb-0 whitespace-pre">
|
|
{line}
|
|
</p>
|
|
))}
|
|
</TerminalCard>
|
|
<p className="!mb-0 mt-4">
|
|
<a
|
|
href="/sample-delivery-report.md"
|
|
download
|
|
className="font-mono text-sm text-accent underline underline-offset-4"
|
|
>
|
|
Download the sample report (sample-delivery-report.md)
|
|
</a>
|
|
</p>
|
|
</section>
|
|
|
|
<section aria-labelledby="weak" className="mt-16 max-w-2xl">
|
|
<h2 id="weak" className="!mt-0 !text-2xl">
|
|
What I do when tests are weak or missing
|
|
</h2>
|
|
<p className="text-base leading-relaxed text-muted">
|
|
AI-built code often arrives with few tests, or with tests that only
|
|
repeat the implementation. I do not start by rewriting. I write the
|
|
expected behavior as cases for the parts that matter most, run them
|
|
against the existing code, and let the failures show what is really
|
|
broken. Then I add a mutation baseline so you can see which tests
|
|
would not notice a bug.
|
|
</p>
|
|
<h2 className="!text-2xl">Why mutation testing</h2>
|
|
<p className="text-base leading-relaxed text-muted">
|
|
Coverage tells you which lines ran during the tests. It does not tell
|
|
you whether the tests would notice a bug in those lines. Mutation
|
|
testing changes the code on purpose and checks that a test fails. That
|
|
is the question you care about. Coverage stays useful as a gap finder:
|
|
it points at code nothing exercises. It is not a goal, and a high
|
|
number alone proves little.
|
|
</p>
|
|
<p className="text-base leading-relaxed text-muted">
|
|
Two systems where I run this: a Rust and Solidity liquidation system
|
|
across 7 chains, with a zero-survivor mutation gate and a coverage
|
|
ratchet, and the domain core of this website, which has its own tests
|
|
and mutation gate.
|
|
</p>
|
|
</section>
|
|
|
|
<section aria-labelledby="guardrails" className="mt-16">
|
|
<SectionHeader
|
|
kicker="guardrails"
|
|
title="Gates that run without me"
|
|
lead="The process does not depend on my discipline on a good day."
|
|
/>
|
|
<ul className="mt-8 grid list-none gap-6 !p-0 md:grid-cols-2">
|
|
{GUARDRAILS.map((item) => (
|
|
<li
|
|
key={item.title}
|
|
className="rounded-lg border border-border bg-surface p-5"
|
|
>
|
|
<h3 className="!mb-2 !mt-0 text-lg font-semibold">
|
|
{item.title}
|
|
</h3>
|
|
<p className="!mb-0 text-base leading-relaxed text-muted">
|
|
{item.text}
|
|
</p>
|
|
</li>
|
|
))}
|
|
</ul>
|
|
</section>
|
|
|
|
<section className="mt-16 border-t border-border pt-10">
|
|
<h2 className="!mt-0 !text-2xl">Want this on your codebase?</h2>
|
|
<p className="mb-6 max-w-2xl text-base text-muted">
|
|
A 20-minute intro call is enough to see whether this fits your team.
|
|
</p>
|
|
<ButtonLink href="/book">Book a 20-minute intro call</ButtonLink>
|
|
</section>
|
|
</Container>
|
|
);
|
|
}
|