Skip to content

Commit f03a11e

Browse files
authored
feat(site): blog essay #9 — "Hand on the Tiller" (course correction & alignment) (#358)
Implements exploration [`0256`](docs/explorations/0256_[x]_HAND_ON_THE_TILLER_COURSE_CORRECTION_AND_ALIGNMENT_ACROSS_EVERY_SYSTEM.md) — blog essay #9. ## What A new essay that reframes **alignment** from the AI-only debate to a property of a **nested stack** of systems (physics ⊃ planet ⊃ society ⊃ technology ⊃ AI), and argues the honest word is the older one: *steering*. The spine is the etymology — *cybernetics*, *governor*, and *govern* all descend from the Greek **κυβερνήτης, the steersman** — so "course correction" becomes literal, not motivational. Grounded in real thinkers (Wiener 1948/1960, Russell's King Midas, Goodhart's Law, Meadows' leverage points, planetary boundaries, Ashby) and cashed out in real xNet receipts: undo, exit, consent, calm, a readable change log, and — the reveal — the sync circuit breaker and integrity checker as *literal* feedback loops the code runs on itself. ## Changes - `site/src/pages/blog/hand-on-the-tiller.astro` — the essay (~15 min read). - `site/src/components/blog/TillerArt.astro` + `TillerHero.astro` — hero: a boat holding a course toward the cosmic-X guiding star, with a dotted zig-zag wake (constant corrections converging on the bearing). Art doubles as the index-card image. - `site/src/components/blog/AlignmentStack.astro` — signature diagram: concentric, slightly-drifting shells (physics→AI), cosmic-X at the core, "the public debate lives here" annotation. - `site/src/components/blog/HonestTiller.astro` — self-audit: the Apollo "90% off course" myth, "aligned to whose values?", one-seam scope, feedback ≠ sufficient. - `site/src/data/blog.ts` — metadata entry (tags `essay/philosophy/decentralization`); `index.astro` — art registered in the card map. - Changelog fragment (`platform`). All art is inline SVG — the page loads nothing third-party (Self-Audit parity). ## Verification - `pnpm --filter site build` passes (109 pages, no errors). - `/blog/hand-on-the-tiller` renders in **light and dark** (hero, diagram, honesty panel verified in the preview); no console errors. - `/blog` index lists the card newest-first; `/blog/rss.xml` includes the post. - Wiener 1960 quote verbatim; "six of nine planetary boundaries" attributed to the 2023 update; the "90% off course" line appears only in the honesty panel, flagged as myth. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
2 parents ac47929 + 688797d commit f03a11e

9 files changed

Lines changed: 1557 additions & 0 deletions

docs/explorations/0256_[x]_HAND_ON_THE_TILLER_COURSE_CORRECTION_AND_ALIGNMENT_ACROSS_EVERY_SYSTEM.md

Lines changed: 769 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
---
2+
// The "one diagram" slot for post #9 (exploration 0256), mirroring the
3+
// HydrostaticBalance / DustBridge / GrowthVsLeverage card idiom (not-prose,
4+
// bordered surface) so the posts read as one publication. Alignment isn't a
5+
// single AI problem; it's a property of a NESTED stack of systems. Concentric
6+
// shells — physics (outer) → planet → society → technology → AI (inner). The
7+
// public debate clusters on the innermost seam (AI ↔ human) while the inner
8+
// shells have drifted off the true axis. The cosmic-X burns at the core. All
9+
// inline SVG; ships nothing third-party (Self-Audit parity).
10+
11+
// Ring centres drift rightward and up as they go inner — the "aligned" axis is
12+
// the dashed plumb line at trueX; the inner shells have wandered off it.
13+
const trueX = 352
14+
const rings = [
15+
{ name: 'Physics', cx: 352, cy: 230, r: 198, op: 0.32 },
16+
{ name: 'Planet', cx: 357, cy: 228, r: 158, op: 0.42 },
17+
{ name: 'Society', cx: 363, cy: 226, r: 119, op: 0.52 },
18+
{ name: 'Technology', cx: 372, cy: 224, r: 81, op: 0.68 },
19+
{ name: 'AI', cx: 382, cy: 222, r: 44, op: 0.9 }
20+
]
21+
const core = rings[rings.length - 1]
22+
23+
// Each layer, and the proxy that captured its goal. The technology↔human seam is
24+
// the only one a small open-source project can actually repair.
25+
const legend = [
26+
{ name: 'Physics', note: 'the one setpoint you can’t game — entropy always votes', xnet: false },
27+
{ name: 'Planet', note: 'steered by GDP; six of nine planetary boundaries crossed', xnet: false },
28+
{ name: 'Society', note: 'steered by metrics and quarterly targets (Goodhart, org edition)', xnet: false },
29+
{ name: 'Technology', note: 'steered by engagement, not wellbeing — the seam xNet repairs', xnet: true },
30+
{ name: 'AI', note: 'steered by a fixed objective standing in for what we actually want', xnet: false }
31+
]
32+
---
33+
34+
<section class="not-prose my-12">
35+
<div class="rounded-2xl border border-border bg-surface/30 p-6 dark:bg-surface/40 lg:p-8">
36+
<h3 class="text-xl font-bold tracking-tight text-gray-900 dark:text-white">
37+
The alignment stack
38+
</h3>
39+
<p class="mt-2 text-sm text-gray-500 dark:text-gray-400">
40+
Alignment is a relationship at a seam between two systems — and the systems
41+
nest. We argue about the innermost seam while the outer ones drift.
42+
</p>
43+
44+
<div class="mt-6 overflow-x-auto">
45+
<svg
46+
viewBox="0 0 720 452"
47+
class="mx-auto block h-auto w-full max-w-xl"
48+
role="img"
49+
aria-label="Concentric shells from physics on the outside to AI at the core; the inner shells have drifted off the true axis, and the public debate clusters on the innermost AI seam."
50+
>
51+
<defs>
52+
<radialGradient id="coreglow" cx="50%" cy="50%" r="50%">
53+
<stop offset="0%" stop-color="#7dd3fc" stop-opacity="0.95" />
54+
<stop offset="45%" stop-color="#38bdf8" stop-opacity="0.4" />
55+
<stop offset="100%" stop-color="#38bdf8" stop-opacity="0" />
56+
</radialGradient>
57+
<linearGradient id="corex" x1="0" y1="0" x2="1" y2="1">
58+
<stop offset="0%" stop-color="#e0f2fe" />
59+
<stop offset="100%" stop-color="#38bdf8" />
60+
</linearGradient>
61+
</defs>
62+
63+
<!-- the true axis: "aligned" is the plumb line the inner shells drift from -->
64+
<line
65+
x1={trueX}
66+
y1="26"
67+
x2={trueX}
68+
y2="426"
69+
stroke="#38bdf8"
70+
stroke-width="1.2"
71+
stroke-dasharray="2 7"
72+
opacity="0.4"
73+
/>
74+
75+
<!-- the nested shells -->
76+
{
77+
rings.map((ring) => (
78+
<g>
79+
<circle
80+
cx={ring.cx}
81+
cy={ring.cy}
82+
r={ring.r}
83+
fill="none"
84+
stroke="#38bdf8"
85+
stroke-width="1.6"
86+
opacity={ring.op}
87+
/>
88+
<text
89+
x={ring.cx}
90+
y={ring.cy - ring.r - 8}
91+
text-anchor="middle"
92+
font-family="ui-sans-serif, system-ui, sans-serif"
93+
font-size="14"
94+
font-weight="600"
95+
fill="#7dd3fc"
96+
>
97+
{ring.name}
98+
</text>
99+
</g>
100+
))
101+
}
102+
103+
<!-- the core: the cosmic-X, burning at the AI seam -->
104+
<g transform={`translate(${core.cx} ${core.cy})`}>
105+
<circle cx="0" cy="0" r="40" fill="url(#coreglow)" />
106+
<g stroke="url(#corex)" stroke-width="5" stroke-linecap="round" transform="translate(-10 -10)">
107+
<line x1="0" y1="0" x2="20" y2="20" />
108+
<line x1="20" y1="0" x2="0" y2="20" />
109+
</g>
110+
</g>
111+
112+
<!-- annotation: the public debate lives on the innermost seam -->
113+
<g font-family="ui-sans-serif, system-ui, sans-serif">
114+
<line
115+
x1={core.cx + core.r + 4}
116+
y1={core.cy}
117+
x2="560"
118+
y2="150"
119+
stroke="#94a3b8"
120+
stroke-width="1.2"
121+
opacity="0.7"
122+
/>
123+
<text x="566" y="140" font-size="13" font-weight="600" fill="#cbd5e1">
124+
the public debate
125+
</text>
126+
<text x="566" y="158" font-size="13" fill="#94a3b8">
127+
lives here
128+
</text>
129+
</g>
130+
</svg>
131+
</div>
132+
133+
<ul class="mt-6 space-y-2.5 border-t border-border pt-5">
134+
{
135+
legend.map((row) => (
136+
<li class="grid gap-1.5 sm:grid-cols-[8rem_1fr] sm:gap-4 sm:items-baseline">
137+
<span
138+
class:list={[
139+
'font-mono text-sm font-semibold',
140+
row.xnet ? 'text-sky-600 dark:text-sky-400' : 'text-gray-500 dark:text-gray-400'
141+
]}
142+
>
143+
{row.name}
144+
</span>
145+
<span class="text-sm leading-relaxed text-gray-700 dark:text-gray-200">{row.note}</span>
146+
</li>
147+
))
148+
}
149+
</ul>
150+
151+
<p class="mt-5 border-t border-border pt-4 text-sm leading-relaxed text-gray-600 dark:text-gray-300">
152+
Bolt an aligned AI onto a technology layer that runs on extraction, on a
153+
society that steers by GDP, on a planet past six of nine limits, and you
154+
haven’t fixed the course — you’ve built a
155+
<span class="font-semibold text-gray-900 dark:text-white">faster way to hold the wrong one</span>.
156+
</p>
157+
</div>
158+
</section>
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
---
2+
// The honesty beat for post #9 (exploration 0256), modeled on HonestExit /
3+
// HonestStar / HonestGarden. An essay that reaches from AI safety to the
4+
// biosphere has to be loud about where its own metaphor thins and where a notes
5+
// app stops being able to help — or it's just another cure-all. So we say plainly
6+
// what "steering" does and doesn't buy.
7+
const rows = [
8+
{
9+
isnt: 'The romantic “off course 90% of the time” line is a myth.',
10+
is: 'A rocket to the Moon isn’t flailing and constantly saving itself — real Apollo was precise, and needed only one to a handful of midcourse corrections. The honest idea underneath is quieter: negative feedback. Sense the gap, close a little of it, repeat. You don’t need the exaggeration.'
11+
},
12+
{
13+
isnt: 'We won’t pretend to know what everything should be aligned to.',
14+
is: 'The whole point is that you can’t freeze “what humans want” into a fixed target and optimize it — that’s the King Midas trap. Be suspicious of anyone who claims the human utility function, us included. Steering keeps the goal open to revision; that’s the feature, not a gap.'
15+
},
16+
{
17+
isnt: 'We won’t pretend software realigns the planet.',
18+
is: 'xNet touches exactly one seam — technology ↔ human. It does nothing about carbon, GDP, or AI safety writ large. What it can do is hand one person back the instruments of course correction over their own information: undo, exit, consent, a machine they can read.'
19+
},
20+
{
21+
isnt: 'We won’t pretend a good tiller picks the destination.',
22+
is: 'Feedback is necessary, not sufficient. A steady hand can hold a bad course. Undo, exit, and consent make correction possible; they don’t choose where you’re going. That part is still yours — which is the only place it should live.'
23+
}
24+
]
25+
---
26+
27+
<section class="not-prose my-12">
28+
<div class="rounded-2xl border border-border bg-surface/30 p-6 dark:bg-surface/40 lg:p-8">
29+
<h3 class="text-xl font-bold tracking-tight text-gray-900 dark:text-white">
30+
An honest heading
31+
</h3>
32+
<p class="mt-2 text-sm text-gray-500 dark:text-gray-400">
33+
A metaphor that oversells itself is just more marketing. Here’s where this
34+
one thins out.
35+
</p>
36+
37+
<ul class="mt-6 space-y-5">
38+
{
39+
rows.map((row) => (
40+
<li class="grid gap-3 sm:grid-cols-[1fr_1.3fr] sm:gap-5">
41+
<div class="flex gap-2.5">
42+
<span class="select-none text-gray-400 dark:text-gray-600">✕</span>
43+
<p class="text-sm leading-relaxed text-gray-500 dark:text-gray-400">{row.isnt}</p>
44+
</div>
45+
<div class="flex gap-2.5">
46+
<span class="select-none text-sky-500">✓</span>
47+
<p class="text-sm leading-relaxed text-gray-700 dark:text-gray-200">{row.is}</p>
48+
</div>
49+
</li>
50+
))
51+
}
52+
</ul>
53+
</div>
54+
</section>
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
---
2+
// Decorative art for blog post #9 (exploration 0256), extracted from TillerHero so
3+
// the same inline SVG backs both the post hero and the blog-index preview card
4+
// (no external assets — Self-Audit parity). A small boat holds a line across open
5+
// water toward a fixed guiding star: the cosmic-X, glowing sky-blue. The dotted
6+
// wake behind it zig-zags — constant small course corrections — and the swings
7+
// shrink as the boat settles onto the bearing. Steering, drawn literally: you
8+
// never arrive at "aligned"; you hold a course.
9+
interface Props {
10+
/** Override the wrapper classes; defaults to full-bleed for hero use. */
11+
class?: string
12+
}
13+
const { class: className = 'pointer-events-none absolute inset-0 h-full w-full' } =
14+
Astro.props
15+
16+
// The guiding star (cosmic-X) and the boat; the bearing line runs between them.
17+
const star = { x: 838, y: 92 }
18+
const boat = { x: 300, y: 236 }
19+
20+
// The wake: the course already sailed, oscillating around the bearing and
21+
// converging on it as it nears the boat (amplitude decays left→right).
22+
const wake = [
23+
[64, 250],
24+
[98, 231],
25+
[131, 251],
26+
[165, 233],
27+
[199, 248],
28+
[232, 234],
29+
[265, 245],
30+
[298, 237]
31+
]
32+
.map(([x, y]) => `${x},${y}`)
33+
.join(' ')
34+
---
35+
36+
<svg
37+
class={className}
38+
viewBox="0 0 1040 340"
39+
preserveAspectRatio="xMidYMid slice"
40+
aria-hidden="true"
41+
>
42+
<defs>
43+
<linearGradient id="tillerbg" x1="0" y1="0" x2="0" y2="1">
44+
<stop offset="0%" stop-color="#071a28" />
45+
<stop offset="52%" stop-color="#0a2233" />
46+
<stop offset="62%" stop-color="#08202f" />
47+
<stop offset="100%" stop-color="#050f18" />
48+
</linearGradient>
49+
<radialGradient id="starglow" cx="50%" cy="50%" r="50%">
50+
<stop offset="0%" stop-color="#7dd3fc" stop-opacity="0.95" />
51+
<stop offset="45%" stop-color="#38bdf8" stop-opacity="0.4" />
52+
<stop offset="100%" stop-color="#38bdf8" stop-opacity="0" />
53+
</radialGradient>
54+
<linearGradient id="starx" x1="0" y1="0" x2="1" y2="1">
55+
<stop offset="0%" stop-color="#e0f2fe" />
56+
<stop offset="100%" stop-color="#38bdf8" />
57+
</linearGradient>
58+
</defs>
59+
60+
<rect width="1040" height="340" fill="url(#tillerbg)" />
61+
62+
<!-- a scatter of faint stars in the night sky -->
63+
<g fill="#7dd3fc" opacity="0.5">
64+
<circle cx="140" cy="60" r="1.4" />
65+
<circle cx="360" cy="42" r="1.1" />
66+
<circle cx="520" cy="80" r="1.5" />
67+
<circle cx="690" cy="52" r="1.2" />
68+
<circle cx="930" cy="150" r="1.3" />
69+
<circle cx="255" cy="110" r="1" />
70+
<circle cx="612" cy="150" r="1" />
71+
</g>
72+
73+
<!-- the sea: horizon and a few settling swells -->
74+
<g stroke="#1e5068" stroke-width="1.4" opacity="0.55" fill="none" stroke-linecap="round">
75+
<line x1="0" y1="212" x2="1040" y2="212" opacity="0.7" />
76+
<path d="M0 250 Q 130 242 260 250 T 520 250 T 780 250 T 1040 250" opacity="0.5" />
77+
<path d="M0 288 Q 150 279 300 288 T 600 288 T 900 288 T 1040 288" opacity="0.35" />
78+
</g>
79+
80+
<!-- the intended course: a faint bearing line from the boat to the guiding star -->
81+
<line
82+
x1={boat.x}
83+
y1={boat.y - 6}
84+
x2={star.x}
85+
y2={star.y + 18}
86+
stroke="#38bdf8"
87+
stroke-width="1.4"
88+
stroke-dasharray="2 7"
89+
opacity="0.5"
90+
/>
91+
92+
<!-- the wake: the course already sailed — constant small corrections, converging -->
93+
<polyline
94+
points={wake}
95+
fill="none"
96+
stroke="#7dd3fc"
97+
stroke-width="2"
98+
stroke-linecap="round"
99+
stroke-linejoin="round"
100+
stroke-dasharray="1 6"
101+
opacity="0.75"
102+
/>
103+
104+
<!-- the boat, heeled slightly to the wind, holding its line -->
105+
<g transform={`translate(${boat.x} ${boat.y}) rotate(-6)`}>
106+
<!-- hull -->
107+
<path
108+
d="M -34 0 Q -20 15 0 15 Q 20 15 34 0 Z"
109+
fill="#0f2f42"
110+
stroke="#7dd3fc"
111+
stroke-width="1.6"
112+
/>
113+
<!-- mast -->
114+
<line x1="-2" y1="0" x2="-2" y2="-44" stroke="#cbd5e1" stroke-width="2" stroke-linecap="round" />
115+
<!-- sail, filled by the wind -->
116+
<path d="M -2 -42 Q 22 -28 16 -4 L -2 -4 Z" fill="#1e5068" stroke="#7dd3fc" stroke-width="1.2" opacity="0.9" />
117+
<!-- tiller: a short bar at the stern, the hand's small correction -->
118+
<line x1="-34" y1="2" x2="-52" y2="-4" stroke="#38bdf8" stroke-width="2.2" stroke-linecap="round" />
119+
</g>
120+
121+
<!-- the guiding star: the cosmic-X, glowing sky-blue, fixed high in the sky -->
122+
<g transform={`translate(${star.x} ${star.y})`}>
123+
<circle cx="0" cy="0" r="40" fill="url(#starglow)" />
124+
<g stroke="url(#starx)" stroke-width="5.5" stroke-linecap="round" transform="translate(-11 -11)">
125+
<line x1="0" y1="0" x2="22" y2="22" />
126+
<line x1="22" y1="0" x2="0" y2="22" />
127+
</g>
128+
</g>
129+
</svg>
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
---
2+
// Hero band for blog post #9 (exploration 0256). The decorative art lives in
3+
// TillerArt.astro so the same inline SVG backs both this hero and the blog-index
4+
// preview card; this component layers the post's title/deck over it.
5+
import TillerArt from './TillerArt.astro'
6+
7+
interface Props {
8+
title: string
9+
deck: string
10+
date: string
11+
readingMinutes: number
12+
tags: string[]
13+
}
14+
const { title, deck, date, readingMinutes, tags } = Astro.props
15+
---
16+
17+
<section class="relative overflow-hidden border-b border-border bg-surface/20 dark:bg-[#050f18]">
18+
<TillerArt />
19+
20+
<div class="relative mx-auto max-w-3xl px-6 pb-14 pt-44 lg:pt-52">
21+
<div class="flex flex-wrap items-center gap-x-3 gap-y-1 text-xs text-sky-200/80">
22+
<time datetime={date}>{date}</time>
23+
<span aria-hidden="true">·</span>
24+
<span>{readingMinutes} min read</span>
25+
{
26+
tags.map((tag) => (
27+
<span class="rounded-full border border-sky-400/30 bg-sky-500/10 px-2 py-0.5 font-mono lowercase text-sky-200">
28+
{tag}
29+
</span>
30+
))
31+
}
32+
</div>
33+
<h1 class="mt-4 text-4xl font-bold tracking-tight text-white drop-shadow lg:text-5xl">
34+
{title}
35+
</h1>
36+
<p class="mt-4 max-w-2xl text-lg leading-relaxed text-gray-300">{deck}</p>
37+
</div>
38+
</section>

0 commit comments

Comments
 (0)