aboutsummaryrefslogtreecommitdiff
path: root/working
diff options
context:
space:
mode:
Diffstat (limited to 'working')
-rw-r--r--working/clock-display-references/2026-07-30-maeda-cosmos-notes.org11
-rw-r--r--working/clock-display-references/2026-07-30-maeda-cosmos-standalone.html422
-rw-r--r--working/clock-display-references/2026-07-30-maeda-line-notes.org11
-rw-r--r--working/clock-display-references/2026-07-30-maeda-line-standalone.html457
-rw-r--r--working/velox-reinstall/velox-reinstall-runbook.org161
-rw-r--r--working/velox-reinstall/velox-uefi-boot-entry-reference.org108
-rw-r--r--working/velox-reinstall/wttrin-bf0457f.bundlebin1826602 -> 0 bytes
7 files changed, 901 insertions, 269 deletions
diff --git a/working/clock-display-references/2026-07-30-maeda-cosmos-notes.org b/working/clock-display-references/2026-07-30-maeda-cosmos-notes.org
new file mode 100644
index 0000000..04d8629
--- /dev/null
+++ b/working/clock-display-references/2026-07-30-maeda-cosmos-notes.org
@@ -0,0 +1,11 @@
+#+TITLE: Companion to the Line applet sent a few minutes ago: a copy
+#+SOURCE: from website
+#+DATE: 2026-07-30 18:48:00 -0500
+
+Companion to the Line applet sent a few minutes ago: a copy of Cosmos (C1, 1995), the orbits piece — 'numbers in orbit'. Delivered as 2026-07-30-maeda-cosmos-standalone.html in this inbox.
+
+Same shape as the Line copy: the <maeda-cosmos> web component plus its model/step/render modules esbuild-bundled inline as an IIFE, so it opens straight from file:// with no server and no network. Verified in Chrome from file:// — canvas 400x300, the month's days riding the rotated ellipse with today red on the sweep hand, seconds odometer live at the right edge, zero console errors.
+
+Controls: hover reshapes every orbit; press-drag pulls a new loop out of the system; the mark at bottom-left clears them and replays the fly-in credit; click the canvas then ESC toggles strip-move mode. Note this one has no readout event, unlike Line.
+
+Source of truth stays ~/code/maeda-tribute (src/pieces/cosmos/); regenerate rather than edit. Reference only — no action needed.
diff --git a/working/clock-display-references/2026-07-30-maeda-cosmos-standalone.html b/working/clock-display-references/2026-07-30-maeda-cosmos-standalone.html
new file mode 100644
index 0000000..bfa9fbb
--- /dev/null
+++ b/working/clock-display-references/2026-07-30-maeda-cosmos-standalone.html
@@ -0,0 +1,422 @@
+<!doctype html>
+<html lang="en">
+<head>
+<meta charset="utf-8">
+<meta name="viewport" content="width=device-width, initial-scale=1">
+<title>Cosmos (C1, 1995) — Maeda × Shiseido tribute</title>
+<style>
+:root{
+ --ground:#151311;
+ --panel:#100f0f;
+ --well:#0a0c0d;
+ --raise:#1a1917;
+ --silver:#bfc4d0;
+ --cream:#f3e7c5;
+ --steel:#969385;
+ --dim:#7c838a;
+ --wash:#2c2f32;
+ --gold:#e2a038;
+ --mono:"BerkeleyMono Nerd Font","Berkeley Mono",monospace;
+}
+*{box-sizing:border-box;margin:0;padding:0}
+html{background:var(--ground);font-size:112%}
+body{font-family:var(--mono);color:var(--silver);padding:2.4rem 2rem 4rem;line-height:1.45;
+ background:radial-gradient(1200px 600px at 70% -10%,#1c1915 0%,transparent 60%),var(--ground)}
+.wrap{max-width:820px;margin:0 auto}
+.eyebrow{color:var(--steel);font-size:.72rem;letter-spacing:.28em;text-transform:uppercase}
+h1{font-size:1.5rem;color:var(--cream);font-weight:600;margin:.35rem 0 .2rem}
+.sub{color:var(--dim);font-size:.9rem;margin-bottom:1.6rem}
+.card{background:linear-gradient(180deg,var(--raise),var(--panel));border:1px solid #262320;
+ border-radius:12px;padding:1.2rem;margin-bottom:1.4rem}
+.stage{background:var(--well);border:1px solid #22201d;border-radius:8px;padding:1rem;
+ display:flex;justify-content:center}
+.wnote{color:var(--dim);font-size:.85rem;margin-top:1rem}
+.wnote b{color:var(--steel);font-weight:600}
+.igrid{display:grid;grid-template-columns:11rem 1fr;gap:.35rem .9rem;margin-top:1rem;
+ font-size:.82rem}
+.ik{color:var(--steel)}
+.iv{color:var(--dim)}
+</style>
+</head>
+<body>
+<div class="wrap">
+ <p class="eyebrow">Waste Time Beautifully · C1</p>
+ <h1>Cosmos — numbers in orbit</h1>
+ <p class="sub">John Maeda for Shiseido, 1995 (Cal0.class) — rebuilt as a web component. Standalone copy, no build step.</p>
+
+ <div class="card">
+ <div class="stage"><maeda-cosmos id="piece"></maeda-cosmos></div>
+ <p class="wnote"><b>Controls:</b> hover to reshape every orbit — the axes track 1.5× the
+ cursor's distance from each orbit's center; press and drag to pull a new loop out of the
+ system; the mark at bottom-left clears them and replays the fly-in credit. Click the
+ canvas first, then <b>ESC</b> toggles strip-move mode (the ground goes orange and the
+ clock strip comes free).</p>
+ <p class="wnote">The days of the month ride a rotated ellipse, today in red on the sweep
+ hand, with a seconds odometer scrolling at the right edge. The month as a gravitational
+ system, days as bodies in orbit, the user as a hand that perturbs the heavens. Time is
+ periodic, not linear.</p>
+ </div>
+
+ <div class="card">
+ <p class="eyebrow">Spec</p>
+ <div class="igrid">
+ <span class="ik">original</span><span class="iv">Cal0.class + UniverseCal, orbit, eint, efloatsin (Java 1.1)</span>
+ <span class="ik">dimensions</span><span class="iv">400×300, black ground, Helvetica 10</span>
+ <span class="ik">collection</span><span class="iv">SFMOMA 99.550</span>
+ <span class="ik">revolution</span><span class="iv">7,500 ms per sweep, phase = wall clock mod cycle — every orbit in lockstep forever; orientation wobbles ±10° on a 15,000 ms sine</span>
+ <span class="ik">interaction</span><span class="iv">every mouse move (not just drag) restyles all orbits; press spawns a zero-axis orbit that inflates as the cursor pulls away</span>
+ <span class="ik">period quirks</span><span class="iv">a cursor-driven rotation angle is computed and stored but never drawn — a dead store in the 1995 bytecode; Mac Java Date bug detected and adjusted</span>
+ <span class="ik">credit</span><span class="iv">chars fly in at 800+80i ms from random scatter, hold 1.5 s, vanish; logo click replays</span>
+ <span class="ik">tests</span><span class="iv">38 (Vitest + fast-check)</span>
+ </div>
+ </div>
+</div>
+
+<script>
+(() => {
+ // src/pieces/cosmos/model.js
+ var TAU = Math.PI * 2;
+ var CREDIT = "designed by john maeda";
+ var FAITHFUL_1995 = {
+ faceW: 400,
+ // applet tag WIDTH=400 HEIGHT=300
+ faceH: 300,
+ cycleMs: 7500,
+ // one revolution, wall-clock modulo
+ wobbleAmp: 10 * Math.PI / 180,
+ // efloatsin(0, 10°, 15000)
+ wobblePeriodMs: 15e3,
+ stretch: 1.5,
+ // axes = 1.5× cursor distance from center
+ initialAxes: [300, 100],
+ // the startup orbit at panel center
+ fontSize: 10,
+ // applet param default; Helvetica plain
+ stripWidth: 20,
+ // stringWidth("59")+6 at 10 px, rounded
+ clockReach: 120,
+ // readout + weekday row extent left of the strip
+ logo: { dx: 8, dy: 8, w: 70, h: 16 }
+ // shiseido.gif box, bottom-left
+ };
+ function sweepPhase(cfg, nowMs) {
+ return nowMs % cfg.cycleMs / cfg.cycleMs * TAU;
+ }
+ function wobbleAngle(cfg, elapsedMs) {
+ return cfg.wobbleAmp * Math.sin(elapsedMs * TAU / cfg.wobblePeriodMs);
+ }
+ function orbitPoint(o, theta, alpha) {
+ const ct = Math.cos(theta);
+ const st = Math.sin(theta);
+ const ca = Math.cos(alpha);
+ const sa = Math.sin(alpha);
+ return {
+ x: o.lmaj * ct * ca - o.lmin * st * sa + o.h,
+ y: o.lmaj * ct * sa + o.lmin * st * ca + o.k
+ };
+ }
+ function dayTheta(day, today, ndays, phase) {
+ return phase + (day - today) * TAU / ndays;
+ }
+ function makeOrbit(x, y, lmaj = 0, lmin = 0) {
+ return { h: x + 0.5, k: y + 0.5, lmaj, lmin, wobbleT: 0 };
+ }
+ function stretchOrbit(cfg, o, mx, my) {
+ return { ...o, lmaj: (mx - o.h) * cfg.stretch, lmin: (my - o.k) * cfg.stretch };
+ }
+ function creditDurations(len) {
+ const chars = [];
+ for (let i = 0; i < len; i++) chars.push(800 + 80 * i);
+ return { chars, sentinel: 800 + 80 * len + 1500 };
+ }
+ function easeLinear(t, a, b, dur) {
+ if (t <= 0) return a;
+ if (t >= dur) return b;
+ return a + (b - a) * t / dur;
+ }
+ function creditDone(len, t) {
+ return t >= creditDurations(len).sentinel;
+ }
+ function stripOffset(cfg, sec, msWithin) {
+ const ld = cfg.fontSize + 1;
+ const siddy = 3 + cfg.fontSize;
+ return -ld * sec - msWithin * ld / 1e3 + siddy - ld;
+ }
+ function logoHit(cfg, x, y) {
+ const { dx, dy, w, h } = cfg.logo;
+ return x < dx + w && y > cfg.faceH - h - dy;
+ }
+ function clockHit(cfg, strip, x, y) {
+ const ld = cfg.fontSize + 1;
+ const left = cfg.faceW - strip.sidex - cfg.clockReach;
+ const right = cfg.faceW - strip.sidex + cfg.stripWidth;
+ return x > left && x < right && y < strip.siddy && y > strip.siddy - ld;
+ }
+
+ // src/pieces/cosmos/step.js
+ function scatterStarts(cfg, rng) {
+ const starts = [];
+ for (let i = 0; i < CREDIT.length; i++) {
+ starts.push({
+ x: Math.floor(rng() * cfg.faceW) * (rng() < 0.5 ? 1 : -1) + cfg.faceW / 2,
+ y: Math.floor(rng() * cfg.faceH) * (rng() < 0.5 ? 1 : -1) + cfg.faceH / 2
+ });
+ }
+ return starts;
+ }
+ function initState(cfg, rng = Math.random) {
+ return {
+ orbits: [makeOrbit(cfg.faceW / 2, cfg.faceH / 2, cfg.initialAxes[0], cfg.initialAxes[1])],
+ credit: { t: 0, starts: scatterStarts(cfg, rng) },
+ strip: { sidex: cfg.stripWidth, siddy: 3 + cfg.fontSize },
+ killPending: false,
+ movable: false,
+ draggingStrip: false,
+ prevHeld: false,
+ prevCursor: null,
+ rng
+ };
+ }
+ function toggleMovable(state) {
+ state.movable = !state.movable;
+ return state;
+ }
+ function step(cfg, state, dtMs, input) {
+ const s = { ...state, strip: { ...state.strip }, credit: { ...state.credit } };
+ const { x, y, held } = input;
+ s.credit.t += dtMs;
+ s.orbits = s.orbits.map((o) => ({ ...o, wobbleT: o.wobbleT + dtMs }));
+ if (x == null) {
+ s.prevHeld = held;
+ return s;
+ }
+ if (held && !s.prevHeld) {
+ if (logoHit(cfg, x, y)) {
+ s.killPending = true;
+ s.credit = { t: 0, starts: scatterStarts(cfg, s.rng) };
+ } else if (clockHit(cfg, s.strip, x, y) || s.movable) {
+ s.draggingStrip = true;
+ } else {
+ s.orbits = [...s.orbits, makeOrbit(x, y)];
+ }
+ }
+ if (held && s.draggingStrip && s.prevCursor) {
+ s.strip.sidex -= x - s.prevCursor.x;
+ s.strip.siddy += y - s.prevCursor.y;
+ }
+ s.orbits = s.orbits.map((o) => stretchOrbit(cfg, o, x, y));
+ if (!held && s.prevHeld) {
+ if (s.killPending) {
+ s.orbits = [s.orbits[0]];
+ s.strip = { sidex: cfg.stripWidth, siddy: 3 + cfg.fontSize };
+ }
+ s.killPending = false;
+ s.draggingStrip = false;
+ }
+ s.prevHeld = held;
+ s.prevCursor = { x, y };
+ return s;
+ }
+
+ // src/lib/calendar.js
+ function isLeapYear(y) {
+ return y % 4 === 0 && (y % 100 !== 0 || y % 400 === 0);
+ }
+ var MDAYS = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
+ function daysInMonth(y, m) {
+ return m === 2 && isLeapYear(y) ? 29 : MDAYS[m - 1];
+ }
+
+ // src/pieces/cosmos/render.js
+ var FACE = { w: 400, h: 300 };
+ var MONTHS = ["jan ", "feb ", "mar ", "apr ", "may ", "jun ", "jul ", "aug ", "sep ", "oct ", "nov ", "dec "];
+ var WEEKDAYS = ["S ", "M ", "T ", "W ", "T ", "F ", "S "];
+ function font(cfg) {
+ return `${cfg.fontSize}px Helvetica, Arial, sans-serif`;
+ }
+ function dateParts(nowMs) {
+ const d = new Date(nowMs);
+ return {
+ year: d.getFullYear(),
+ month: d.getMonth() + 1,
+ // 1-12
+ day: d.getDate(),
+ weekday: d.getDay(),
+ hours: d.getHours(),
+ minutes: d.getMinutes(),
+ seconds: d.getSeconds(),
+ msWithin: nowMs % 1e3
+ };
+ }
+ function drawOrbit(ctx, cfg, o, dp, phase, dim) {
+ const ndays = daysInMonth(dp.year, dp.month);
+ const alpha = wobbleAngle(cfg, o.wobbleT);
+ const daystr = `${dp.day} ${dp.year}`;
+ const monthstr = MONTHS[dp.month - 1];
+ for (let d = 1; d <= ndays; d++) {
+ const p = orbitPoint(o, dayTheta(d, dp.day, ndays, phase), alpha);
+ if (d === dp.day) {
+ ctx.fillStyle = "#f00";
+ ctx.fillText(daystr, p.x, p.y);
+ ctx.fillText(monthstr, p.x - ctx.measureText(monthstr).width, p.y);
+ } else {
+ ctx.fillStyle = dim ? "#808080" : "#fff";
+ ctx.fillText(String(d), p.x, p.y);
+ }
+ }
+ }
+ function drawStrip(ctx, cfg, state, dp) {
+ const ld = cfg.fontSize + 1;
+ const { sidex, siddy } = state.strip;
+ const x = FACE.w - sidex;
+ const tileH = ld * 60;
+ const off = stripOffset(cfg, dp.seconds, dp.msWithin) + (siddy - (3 + cfg.fontSize));
+ ctx.save();
+ ctx.beginPath();
+ ctx.rect(x, 0, cfg.stripWidth, FACE.h);
+ ctx.clip();
+ ctx.fillStyle = "#404040";
+ ctx.fillRect(x, 0, cfg.stripWidth, FACE.h);
+ ctx.fillStyle = "#808080";
+ for (const tile of [-1, 0, 1]) {
+ for (let i = 0; i < 60; i++) {
+ const y = off + tile * tileH + i * ld + ld;
+ if (y > -ld && y < FACE.h + ld) {
+ ctx.fillText(String(i).padStart(2, "0"), x + 3, y);
+ }
+ }
+ }
+ ctx.restore();
+ ctx.fillStyle = "#f00";
+ ctx.fillText(String(dp.seconds).padStart(2, "0"), x + 3, siddy);
+ const h12 = dp.hours % 12 === 0 ? 12 : dp.hours % 12;
+ const clock = `${h12}${dp.minutes < 10 ? ":0" : ":"}${dp.minutes}:`;
+ const cx = x + 3 - ctx.measureText(clock).width;
+ ctx.fillText(clock, cx, siddy);
+ let wx = cx - ctx.measureText("S M T W T F S ").width;
+ for (let i = 0; i < 7; i++) {
+ ctx.fillStyle = i === dp.weekday ? "#f00" : "#808080";
+ ctx.fillText(WEEKDAYS[i], wx, siddy);
+ wx += ctx.measureText(WEEKDAYS[i]).width;
+ }
+ }
+ function drawCredit(ctx, cfg, state) {
+ const { t, starts } = state.credit;
+ if (creditDone(CREDIT.length, t)) return;
+ const durs = creditDurations(CREDIT.length);
+ let fx = (FACE.w - ctx.measureText(CREDIT).width) / 2 + 1;
+ const fy = FACE.h / 2 + cfg.fontSize / 2;
+ ctx.fillStyle = "#fff";
+ for (let i = 0; i < CREDIT.length; i++) {
+ const ch = CREDIT[i];
+ const x = easeLinear(t, starts[i].x, fx, durs.chars[i]);
+ const y = easeLinear(t, starts[i].y, fy, durs.chars[i]);
+ ctx.fillText(ch, x, y);
+ fx += ctx.measureText(ch).width;
+ }
+ }
+ function drawLogo(ctx, cfg) {
+ const { dx, dy, h } = cfg.logo;
+ ctx.fillStyle = "#808080";
+ ctx.fillText("shiseido", dx, FACE.h - dy - h / 2 + cfg.fontSize / 2);
+ }
+ function draw(ctx, cfg, state, nowMs) {
+ const dp = dateParts(nowMs);
+ ctx.fillStyle = state.movable ? "#e08000" : "#000";
+ ctx.fillRect(0, 0, FACE.w, FACE.h);
+ ctx.font = font(cfg);
+ ctx.textBaseline = "alphabetic";
+ drawStrip(ctx, cfg, state, dp);
+ const phase = sweepPhase(cfg, nowMs);
+ state.orbits.forEach((o, i) => {
+ drawOrbit(ctx, cfg, o, dp, phase, state.killPending && i > 0);
+ });
+ drawLogo(ctx, cfg);
+ drawCredit(ctx, cfg, state);
+ ctx.strokeStyle = "#fff";
+ ctx.lineWidth = 1;
+ ctx.strokeRect(0.5, 0.5, FACE.w - 1, FACE.h - 1);
+ }
+
+ // src/lib/loop.js
+ var STEP_MS = 30;
+ function startLoop({ stepFn, renderFn, stepMs = STEP_MS }) {
+ let acc = 0;
+ let last = null;
+ let raf = null;
+ let running = true;
+ function frame(ts) {
+ if (!running) return;
+ if (last === null) last = ts;
+ acc += Math.min(ts - last, 250);
+ last = ts;
+ while (acc >= stepMs) {
+ stepFn(stepMs);
+ acc -= stepMs;
+ }
+ renderFn();
+ raf = requestAnimationFrame(frame);
+ }
+ raf = requestAnimationFrame(frame);
+ return () => {
+ running = false;
+ if (raf) cancelAnimationFrame(raf);
+ };
+ }
+
+ // src/pieces/cosmos/index.js
+ var MaedaCosmos = class extends HTMLElement {
+ connectedCallback() {
+ const canvas = document.createElement("canvas");
+ canvas.width = FACE.w;
+ canvas.height = FACE.h;
+ canvas.style.cssText = "display:block;width:100%;max-width:400px;cursor:crosshair;touch-action:none";
+ canvas.tabIndex = 0;
+ this.appendChild(canvas);
+ const ctx = canvas.getContext("2d");
+ const frozen = this.getAttribute("frozen-now");
+ const nowMs = () => frozen ? Number(frozen) * 1e3 : Date.now();
+ const cfg = FAITHFUL_1995;
+ let state = initState(cfg);
+ const input = { x: null, y: null, held: false };
+ const toFace = (ev) => {
+ const r = canvas.getBoundingClientRect();
+ return {
+ x: (ev.clientX - r.left) * (FACE.w / r.width),
+ y: (ev.clientY - r.top) * (FACE.h / r.height)
+ };
+ };
+ canvas.addEventListener("pointermove", (ev) => {
+ Object.assign(input, toFace(ev));
+ });
+ canvas.addEventListener("pointerdown", (ev) => {
+ canvas.setPointerCapture(ev.pointerId);
+ canvas.focus();
+ Object.assign(input, toFace(ev));
+ input.held = true;
+ });
+ const release = () => {
+ input.held = false;
+ };
+ canvas.addEventListener("pointerup", release);
+ canvas.addEventListener("pointercancel", release);
+ canvas.addEventListener("keydown", (ev) => {
+ if (ev.key === "Escape") toggleMovable(state);
+ });
+ this._stop = startLoop({
+ stepFn: (dtMs) => {
+ state = step(cfg, state, dtMs, input);
+ },
+ renderFn: () => draw(ctx, cfg, state, nowMs())
+ });
+ }
+ disconnectedCallback() {
+ if (this._stop) this._stop();
+ }
+ };
+ customElements.define("maeda-cosmos", MaedaCosmos);
+})();
+
+</script>
+</body>
+</html>
diff --git a/working/clock-display-references/2026-07-30-maeda-line-notes.org b/working/clock-display-references/2026-07-30-maeda-line-notes.org
new file mode 100644
index 0000000..ba50a80
--- /dev/null
+++ b/working/clock-display-references/2026-07-30-maeda-line-notes.org
@@ -0,0 +1,11 @@
+#+TITLE: Copy of the Line applet (C2, 1997) from the Maeda x Shiseido
+#+SOURCE: from website
+#+DATE: 2026-07-30 18:38:41 -0500
+
+Copy of the Line applet (C2, 1997) from the Maeda x Shiseido tribute — the diagonal timeline piece, 'zoom through time'. Delivered as 2026-07-30-1838-from-website-2026-07-30-maeda-line-standalone.html in this inbox.
+
+It is a single self-contained file: the <maeda-line> web component and its model/step/render modules are esbuild-bundled inline as an IIFE, so it opens straight from file:// with no server, no build step, and no network. Verified rendering in Chrome from file:// — canvas 460x400, zero console errors, live readout wired.
+
+Controls: move the pointer along the diagonal to aim, press and hold to zoom continuously into that moment, release to float back out. Full zoom is exactly 60 seconds and the release is symmetric.
+
+Source of truth stays ~/code/maeda-tribute (src/pieces/line/); this copy is a snapshot, so regenerate rather than edit it if the piece changes. Sent for reference — no action needed unless you want it wired into the panel-widget gallery.
diff --git a/working/clock-display-references/2026-07-30-maeda-line-standalone.html b/working/clock-display-references/2026-07-30-maeda-line-standalone.html
new file mode 100644
index 0000000..783939c
--- /dev/null
+++ b/working/clock-display-references/2026-07-30-maeda-line-standalone.html
@@ -0,0 +1,457 @@
+<!doctype html>
+<html lang="en">
+<head>
+<meta charset="utf-8">
+<meta name="viewport" content="width=device-width, initial-scale=1">
+<title>Line (C2, 1997) — Maeda × Shiseido tribute</title>
+<style>
+:root{
+ --ground:#151311;
+ --panel:#100f0f;
+ --well:#0a0c0d;
+ --raise:#1a1917;
+ --silver:#bfc4d0;
+ --cream:#f3e7c5;
+ --steel:#969385;
+ --dim:#7c838a;
+ --wash:#2c2f32;
+ --gold:#e2a038;
+ --mono:"BerkeleyMono Nerd Font","Berkeley Mono",monospace;
+}
+*{box-sizing:border-box;margin:0;padding:0}
+html{background:var(--ground);font-size:112%}
+body{font-family:var(--mono);color:var(--silver);padding:2.4rem 2rem 4rem;line-height:1.45;
+ background:radial-gradient(1200px 600px at 70% -10%,#1c1915 0%,transparent 60%),var(--ground)}
+.wrap{max-width:820px;margin:0 auto}
+.eyebrow{color:var(--steel);font-size:.72rem;letter-spacing:.28em;text-transform:uppercase}
+h1{font-size:1.5rem;color:var(--cream);font-weight:600;margin:.35rem 0 .2rem}
+.sub{color:var(--dim);font-size:.9rem;margin-bottom:1.6rem}
+.card{background:linear-gradient(180deg,var(--raise),var(--panel));border:1px solid #262320;
+ border-radius:12px;padding:1.2rem;margin-bottom:1.4rem}
+.stage{background:var(--well);border:1px solid #22201d;border-radius:8px;padding:1rem;
+ display:flex;justify-content:center}
+.readout{margin-top:.8rem;color:var(--gold);font-size:.82rem;letter-spacing:.06em}
+.wnote{color:var(--dim);font-size:.85rem;margin-top:1rem}
+.wnote b{color:var(--steel);font-weight:600}
+.igrid{display:grid;grid-template-columns:11rem 1fr;gap:.35rem .9rem;margin-top:1rem;
+ font-size:.82rem}
+.ik{color:var(--steel)}
+.iv{color:var(--dim)}
+</style>
+</head>
+<body>
+<div class="wrap">
+ <p class="eyebrow">Waste Time Beautifully · C2</p>
+ <h1>Line — zoom through time</h1>
+ <p class="sub">John Maeda for Shiseido, 1997 (cal1.class) — rebuilt as a web component. Standalone copy, no build step.</p>
+
+ <div class="card">
+ <div class="stage"><maeda-line id="piece"></maeda-line></div>
+ <div class="readout" id="readout">scale — · counter —</div>
+ <p class="wnote"><b>Controls:</b> move the pointer along the diagonal to aim; press and
+ hold to zoom continuously into that moment; release and you float back out. Full zoom
+ is exactly 60 seconds, and the release is symmetric.</p>
+ <p class="wnote">Time as a single line — <b>diagonal</b>, bottom-left to top-right, the
+ detail every written description of this applet gets wrong. Maeda's note: it reflects
+ the relativity and comparability of time intervals. The zoom is the content.</p>
+ </div>
+
+ <div class="card">
+ <p class="eyebrow">Spec</p>
+ <div class="igrid">
+ <span class="ik">original</span><span class="iv">cal1.class, 12,339 bytes, single class, self-contained (Java 1.1)</span>
+ <span class="ik">dimensions</span><span class="iv">460×400, black ground, Helvetica throughout</span>
+ <span class="ik">collection</span><span class="iv">SFMOMA 99.554</span>
+ <span class="ik">zoom plateaus</span><span class="iv">72px per day / hour / minute / second — scn 1 → 72 → 1,728 → 103,680 → 6,220,800 px/day</span>
+ <span class="ik">easing</span><span class="iv">counter at 20 increments/sec over segments [150, 250, 350, 450]</span>
+ <span class="ik">labels</span><span class="iv">font = min(72, unit spacing); text under 5px degrades to a line; gray ramps 128→255 as a unit matures; the current unit is always red</span>
+ <span class="ik">period quirks</span><span class="iv">Mac JVM patch capped zoom at hour level; an unused HAPPY NEW YEAR string ships in the bytecode</span>
+ <span class="ik">tests</span><span class="iv">33 (Vitest + fast-check)</span>
+ </div>
+ </div>
+</div>
+
+<script>
+(() => {
+ // src/lib/calendar.js
+ function epochDayFromCivil(y, m, d) {
+ const yy = y - (m <= 2 ? 1 : 0);
+ const era = Math.floor(yy / 400);
+ const yoe = yy - era * 400;
+ const doy = Math.floor((153 * (m + (m > 2 ? -3 : 9)) + 2) / 5) + d - 1;
+ const doe = yoe * 365 + Math.floor(yoe / 4) - Math.floor(yoe / 100) + doy;
+ return era * 146097 + doe - 719468;
+ }
+ function civilFromEpochDay(ed) {
+ const z = ed + 719468;
+ const era = Math.floor(z / 146097);
+ const doe = z - era * 146097;
+ const yoe = Math.floor(
+ (doe - Math.floor(doe / 1460) + Math.floor(doe / 36524) - Math.floor(doe / 146096)) / 365
+ );
+ const y = yoe + era * 400;
+ const doy = doe - (365 * yoe + Math.floor(yoe / 4) - Math.floor(yoe / 100));
+ const mp = Math.floor((5 * doy + 2) / 153);
+ const d = doy - Math.floor((153 * mp + 2) / 5) + 1;
+ const m = mp + (mp < 10 ? 3 : -9);
+ return { y: y + (m <= 2 ? 1 : 0), m, d };
+ }
+
+ // src/pieces/line/model.js
+ var DAY = 86400;
+ var FAITHFUL_1997 = {
+ stops: [1, 72, 1728, 103680, 6220800],
+ segments: [150, 250, 350, 450],
+ incsPerSec: 20
+ };
+ function totalIncrements(cfg) {
+ return cfg.segments.reduce((a, b) => a + b, 0);
+ }
+ function scaleForCounter(cfg, counter) {
+ const total = totalIncrements(cfg);
+ const c = Math.max(0, Math.min(total, counter));
+ let acc = 0;
+ for (let i = 0; i < cfg.segments.length; i++) {
+ const seg = cfg.segments[i];
+ if (c <= acc + seg) {
+ const f = (c - acc) / seg;
+ return cfg.stops[i] + f * (cfg.stops[i + 1] - cfg.stops[i]);
+ }
+ acc += seg;
+ }
+ return cfg.stops[cfg.stops.length - 1];
+ }
+ function advanceCounter(cfg, counter, dtMs, held) {
+ const d = cfg.incsPerSec * dtMs / 1e3;
+ const next = held ? counter + d : counter - d;
+ return Math.max(0, Math.min(totalIncrements(cfg), next));
+ }
+ function pxOfTime(view, t) {
+ return (t - view.focus) * view.scale / DAY + view.anchorPx;
+ }
+ function timeOfPx(view, px) {
+ return (px - view.anchorPx) * DAY / view.scale + view.focus;
+ }
+ var MAX_FONT = 72;
+ var MIN_TEXT_PX = 5;
+ function fontSizeFor(spacingPx) {
+ return Math.min(MAX_FONT, spacingPx);
+ }
+ function textVisible(fontSize) {
+ return fontSize >= MIN_TEXT_PX;
+ }
+ function grayFor(fontSize) {
+ return Math.floor(Math.min(MAX_FONT, fontSize) * 127 / MAX_FONT) + 128;
+ }
+ var FIXED_UNITS = { second: 1, minute: 60, hour: 3600, day: DAY };
+ function* calendarTicks(unit, t0, t1) {
+ let { y, m } = civilFromEpochDay(Math.floor(t0 / DAY));
+ const stride = unit === "decade" ? 10 : unit === "century" ? 100 : 1;
+ if (unit === "month") {
+ for (; ; ) {
+ const t = epochDayFromCivil(y, m, 1) * DAY;
+ if (t >= t0) break;
+ m++;
+ if (m > 12) m = 1, y++;
+ }
+ for (; ; ) {
+ const t = epochDayFromCivil(y, m, 1) * DAY;
+ if (t > t1) return;
+ yield t;
+ m++;
+ if (m > 12) m = 1, y++;
+ }
+ } else {
+ let yy = Math.ceil(y / stride) * stride;
+ if (epochDayFromCivil(yy, 1, 1) * DAY < t0) yy += stride;
+ while (epochDayFromCivil(yy - stride, 1, 1) * DAY >= t0) yy -= stride;
+ for (; ; ) {
+ const t = epochDayFromCivil(yy, 1, 1) * DAY;
+ if (t > t1) return;
+ if (t >= t0) yield t;
+ yy += stride;
+ }
+ }
+ }
+ function ticksInRange(unit, t0, t1) {
+ if (unit in FIXED_UNITS) {
+ const w = FIXED_UNITS[unit];
+ const out = [];
+ for (let t = Math.ceil(t0 / w) * w; t <= t1; t += w) out.push(t);
+ return out;
+ }
+ return [...calendarTicks(unit, t0, t1)];
+ }
+ var MONTHS = [
+ "JANUARY",
+ "FEBRUARY",
+ "MARCH",
+ "APRIL",
+ "MAY",
+ "JUNE",
+ "JULY",
+ "AUGUST",
+ "SEPTEMBER",
+ "OCTOBER",
+ "NOVEMBER",
+ "DECEMBER"
+ ];
+ function formatMonth(m) {
+ return MONTHS[m - 1];
+ }
+ function formatDay(m, d) {
+ return `${m}/${d}`;
+ }
+ function formatHour(h) {
+ const twelve = h % 12 === 0 ? 12 : h % 12;
+ return { text: ` ${twelve}`, suffix: h >= 12 ? "pm" : "am" };
+ }
+ function formatMinute(mm) {
+ return `:${String(mm).padStart(2, "0")}`;
+ }
+
+ // src/pieces/line/step.js
+ function initState(cfg, range, lineLenPx) {
+ return {
+ counter: 0,
+ scale: scaleForCounter(cfg, 0),
+ focus: 0,
+ // epoch seconds under the anchor pixel
+ anchorPx: 0,
+ // pixel along the line where focus projects
+ range,
+ // {tMin, tMax} or null for the unbounded twist
+ lineLenPx
+ };
+ }
+ function step(cfg, s, dtMs, input) {
+ const cursorPx = Math.max(0, Math.min(s.lineLenPx, input.cursorPx));
+ let { focus, anchorPx } = s;
+ if (input.held || s.counter > 0) {
+ focus = timeOfPx({ focus: s.focus, scale: s.scale, anchorPx: s.anchorPx }, cursorPx);
+ anchorPx = cursorPx;
+ }
+ const counter = advanceCounter(cfg, s.counter, dtMs, input.held);
+ const scale = scaleForCounter(cfg, counter);
+ if (!input.held && counter < cfg.segments[0]) {
+ const target = cursorPx * DAY;
+ focus += (target - focus) / (counter + 1);
+ anchorPx = cursorPx;
+ }
+ if (s.range) {
+ focus = Math.max(s.range.tMin, Math.min(s.range.tMax, focus));
+ }
+ return { ...s, counter, scale, focus, anchorPx };
+ }
+
+ // src/pieces/line/render.js
+ var LEVELS = [
+ { unit: "month", secs: 30 * DAY },
+ { unit: "day", secs: DAY },
+ { unit: "hour", secs: 3600 },
+ { unit: "minute", secs: 60 },
+ { unit: "second", secs: 1 }
+ ];
+ var FACE = { w: 460, h: 400 };
+ function lineOrigin(state) {
+ const margin = (FACE.h - state.lineLenPx) / 2;
+ return { mx: FACE.w - FACE.h + margin, my: margin };
+ }
+ function labelFor(unit, t) {
+ const dayIdx = Math.floor(t / DAY);
+ const civ = civilFromEpochDay(dayIdx);
+ const rem = t - dayIdx * DAY;
+ const hh = Math.floor(rem / 3600);
+ const mm = Math.floor(rem % 3600 / 60);
+ const ss = Math.floor(rem % 60);
+ switch (unit) {
+ case "month":
+ return formatMonth(civ.m);
+ case "day":
+ return formatDay(civ.m, civ.d);
+ case "hour": {
+ const h = formatHour(hh);
+ return h.text + h.suffix;
+ }
+ case "minute":
+ return formatMinute(mm);
+ case "second":
+ return formatMinute(ss);
+ default:
+ return "";
+ }
+ }
+ function sameTick(unit, t, now) {
+ const w = { second: 1, minute: 60, hour: 3600, day: DAY }[unit];
+ if (w) return Math.floor(t / w) === Math.floor(now / w);
+ const a = civilFromEpochDay(Math.floor(t / DAY));
+ const b = civilFromEpochDay(Math.floor(now / DAY));
+ return a.y === b.y && a.m === b.m;
+ }
+ function draw(ctx, state, nowSec) {
+ const { mx, my } = lineOrigin(state);
+ ctx.fillStyle = "#000";
+ ctx.fillRect(0, 0, FACE.w, FACE.h);
+ const view = { focus: state.focus, scale: state.scale, anchorPx: state.anchorPx };
+ const tA = Math.max(
+ state.range ? state.range.tMin : -Infinity,
+ state.focus - state.anchorPx * DAY / state.scale
+ );
+ const tB = Math.min(
+ state.range ? state.range.tMax : Infinity,
+ state.focus + (state.lineLenPx - state.anchorPx) * DAY / state.scale
+ );
+ ctx.strokeStyle = "#666";
+ ctx.beginPath();
+ ctx.moveTo(mx, FACE.h - my);
+ ctx.lineTo(mx + state.lineLenPx, FACE.h - my - state.lineLenPx);
+ ctx.stroke();
+ const colWidth = {};
+ for (let i = LEVELS.length - 1; i >= 0; i--) {
+ const { unit, secs } = LEVELS[i];
+ const spacing = secs * state.scale / DAY;
+ if (spacing < 2 && unit !== "month") {
+ colWidth[unit] = 0;
+ continue;
+ }
+ const size = Math.floor(fontSizeFor(spacing));
+ colWidth[unit] = textVisible(size) ? size * 2.2 : 0;
+ }
+ for (let i = LEVELS.length - 1; i >= 0; i--) {
+ const { unit, secs } = LEVELS[i];
+ const spacing = secs * state.scale / DAY;
+ if (spacing < 2 && unit !== "month") continue;
+ const size = unit === "month" ? Math.floor(Math.min(72, 11 + state.scale)) : Math.floor(fontSizeFor(spacing));
+ const gray = unit === "month" ? 255 : grayFor(size);
+ let offset = 0;
+ for (let j = LEVELS.length - 1; j > i; j--) offset += colWidth[LEVELS[j].unit];
+ ctx.font = `${Math.max(size, 1)}px Helvetica, Arial, sans-serif`;
+ for (const t of ticksInRange(unit, tA, tB)) {
+ const n = pxOfTime(view, t);
+ if (n < 0 || n > state.lineLenPx) continue;
+ const x = mx + n;
+ const y = FACE.h - my - n;
+ const isNow = sameTick(unit, t, nowSec);
+ ctx.strokeStyle = ctx.fillStyle = isNow ? "#f00" : `rgb(${gray},${gray},${gray})`;
+ ctx.beginPath();
+ ctx.moveTo(x, y);
+ ctx.lineTo(x + 3, y);
+ ctx.stroke();
+ const text = labelFor(unit, t);
+ if (textVisible(size)) {
+ const w = ctx.measureText(text).width;
+ ctx.fillText(text, x - w - offset, y);
+ } else {
+ ctx.beginPath();
+ ctx.moveTo(x - 4 - offset, y);
+ ctx.lineTo(x - offset, y);
+ ctx.stroke();
+ }
+ }
+ }
+ ctx.fillStyle = "#ccc";
+ ctx.font = "15px Helvetica, Arial, sans-serif";
+ const label = `${Math.round(state.scale)}X${state.counter >= 1200 ? " (MAX)" : ""}`;
+ ctx.fillText(label, 3, 16);
+ }
+
+ // src/lib/loop.js
+ var STEP_MS = 30;
+ function startLoop({ stepFn, renderFn, stepMs = STEP_MS }) {
+ let acc = 0;
+ let last = null;
+ let raf = null;
+ let running = true;
+ function frame(ts) {
+ if (!running) return;
+ if (last === null) last = ts;
+ acc += Math.min(ts - last, 250);
+ last = ts;
+ while (acc >= stepMs) {
+ stepFn(stepMs);
+ acc -= stepMs;
+ }
+ renderFn();
+ raf = requestAnimationFrame(frame);
+ }
+ raf = requestAnimationFrame(frame);
+ return () => {
+ running = false;
+ if (raf) cancelAnimationFrame(raf);
+ };
+ }
+
+ // src/pieces/line/index.js
+ var MaedaLine = class extends HTMLElement {
+ connectedCallback() {
+ const canvas = document.createElement("canvas");
+ canvas.width = FACE.w;
+ canvas.height = FACE.h;
+ canvas.style.cssText = "display:block;width:100%;max-width:460px;cursor:crosshair;touch-action:none";
+ this.appendChild(canvas);
+ const ctx = canvas.getContext("2d");
+ const frozen = this.getAttribute("frozen-now");
+ const nowSec = () => frozen ? Number(frozen) : Date.now() / 1e3;
+ const { y } = (() => {
+ const d = new Date(nowSec() * 1e3);
+ return { y: d.getUTCFullYear() };
+ })();
+ const t0 = epochDayFromCivil(y, 1, 1) * DAY;
+ const t1 = epochDayFromCivil(y + 1, 1, 1) * DAY;
+ const lineLen = Math.round((t1 - t0) / DAY);
+ const cfg = FAITHFUL_1997;
+ let state = initState(cfg, { tMin: 0, tMax: t1 - t0 }, lineLen);
+ state.focus = nowSec() - t0;
+ state.anchorPx = state.focus / DAY;
+ const input = { cursorPx: state.anchorPx, held: false };
+ const toLinePx = (ev) => {
+ const r = canvas.getBoundingClientRect();
+ const sx = FACE.w / r.width;
+ const x = (ev.clientX - r.left) * sx;
+ const yy = (ev.clientY - r.top) * (FACE.h / r.height);
+ const margin = (FACE.h - lineLen) / 2;
+ const mx = FACE.w - FACE.h + margin;
+ return (x - mx + (FACE.h - margin - yy)) / 2;
+ };
+ canvas.addEventListener("pointermove", (ev) => {
+ input.cursorPx = toLinePx(ev);
+ });
+ canvas.addEventListener("pointerdown", (ev) => {
+ canvas.setPointerCapture(ev.pointerId);
+ input.cursorPx = toLinePx(ev);
+ input.held = true;
+ });
+ const release = () => {
+ input.held = false;
+ };
+ canvas.addEventListener("pointerup", release);
+ canvas.addEventListener("pointercancel", release);
+ this._stop = startLoop({
+ stepFn: (dtMs) => {
+ state = step(cfg, state, dtMs, input);
+ },
+ renderFn: () => {
+ draw(ctx, state, nowSec() - t0);
+ this.dispatchEvent(new CustomEvent("readout", {
+ detail: { scale: state.scale, counter: state.counter }
+ }));
+ }
+ });
+ }
+ disconnectedCallback() {
+ if (this._stop) this._stop();
+ }
+ };
+ customElements.define("maeda-line", MaedaLine);
+})();
+
+</script>
+<script>
+document.getElementById("piece").addEventListener("readout", (e) => {
+ const { scale, counter } = e.detail;
+ document.getElementById("readout").textContent =
+ "scale " + Number(scale).toFixed(3) + " · counter " + Math.round(counter);
+});
+</script>
+</body>
+</html>
diff --git a/working/velox-reinstall/velox-reinstall-runbook.org b/working/velox-reinstall/velox-reinstall-runbook.org
deleted file mode 100644
index 0c14946..0000000
--- a/working/velox-reinstall/velox-reinstall-runbook.org
+++ /dev/null
@@ -1,161 +0,0 @@
-#+TITLE: Velox Reinstall Runbook — DR Test of archangel + archsetup
-#+AUTHOR: Craig Jennings
-#+DATE: 2026-08-13
-
-Context: velox's mainboard swapped Intel → AMD (Ryzen AI 9 HX 370, Radeon
-890M, 96GB RAM). Old SSD intact but the new board's NVRAM has no boot entry,
-and velox is ZFS root + ZFSBootMenu, so a stock Arch USB can't even read the
-pool. Decision: full reinstall via archangel + archsetup, run deliberately as
-a disaster-recovery test of the ISO and scripts before the Sunday flight.
-Recent backup in hand; ratio available as the working machine.
-
-Fallback ordering if the test finds a real gap:
-- Before partitioning starts: the old system is intact — the ZBM repair
- route (efibootmgr entry pointing at the ZBM loader on the ESP, then
- amd-ucode swap in a chroot) is still available.
-- After partitioning: the floor is a manual Arch install; the backup makes
- that survivable.
-
-* Phase 0 — Preflight on ratio (agent-driven, done before you leave the desk)
-
-- [ ] Rebuild the ISO with archsetup baked in: the 2026-08-02 ISO predates
- the microcode vendor-detection fix (archsetup, 2026-08-08) and was built
- without ARCHSETUP_DIR at all.
- #+begin_src sh
- cd ~/code/archangel && sudo ARCHSETUP_DIR="$HOME/code/archsetup" ./build.sh
- #+end_src
- Two traps in that one line, and either alone silently produces a bare ISO
- with archsetup absent (archangel, 2026-08-20). The =VAR=value= form is
- required because sudo's =env_reset= discards an exported variable. And
- =$HOME= is required because zsh does not expand a tilde on the right-hand
- side of an assignment — the earlier =ARCHSETUP_DIR=~/code/archsetup= here
- passed the literal string. build.sh now warns and reports baked/not-baked
- in its closing summary, so the failure is visible rather than silent.
-- [ ] build.sh fixes before the final rebuild (archangel repo):
- - rsync exclude for =.ai= (keeps =archsetup/.ai/private-design/= — the
- credential audit — off the portable USB stick).
- - copy =installer/velox-*.conf= to =airootfs/root/= so the machine profile
- is on the ISO at =/root/velox-zfs.conf=.
-- [ ] Verify the ISO carries: =/code/archsetup= (with =install_cpu_microcode=),
- =/root/velox-zfs.conf=, no =.ai/private-design=. Loop-mount or unsquashfs
- spot-check.
-- [X] USB ready (done 2026-08-13 15:25): the new ISO was copied to the Ventoy
- drive, sha256-verified against the source, and the 2026-04-09 + 2026-06-16
- archangel ISOs removed. Boot the stick and pick
- =archangel-2026-08-13-vmlinuz-6.18.43-lts-x86_64.iso= from the Ventoy menu.
-
-* Phase 1 — UEFI setup on velox (BIOS screen, before any boot)
-
-- [ ] Disable Secure Boot. Mandatory — the ZFS kernel modules are unsigned;
- the new board ships with it enforced by factory default.
-- [ ] Set the system clock. The board swap reset the RTC to 2025-01-01;
- a wrong clock breaks TLS and pacman signature checks in the live env.
- Rough accuracy is fine — NTP tightens it once networked.
-- [ ] While you're in setup: check boot-order UI shows the USB.
-
-* Phase 2 — Salvage pass (live ISO, BEFORE running the installer) — REQUIRED
-
-NOT optional insurance. Verified 2026-08-13: velox's newest truenas backup is
-DAILY.0 = 2026-07-06 — five weeks stale. The backup timer on velox broke
-around Jul 6 (truenas itself only went dark Jul 24, and it's back now; ratio
-and mybitch backed up today). Everything since Jul 6 exists only on the old
-SSD — including =wolf.conf.gpg= (created Jul 29), which is therefore in NO
-backup at all. This pass also keeps the repair fallback alive until
-partitioning starts.
-
-- [ ] Network up (=nmtui= or ethernet), then confirm clock: =timedatectl=.
-- [ ] Import the old pool read-only and unlock:
- #+begin_src sh
- zpool import -N -o readonly=on -R /mnt zroot
- zfs load-key zroot # passphrase prompt
- zfs mount zroot/ROOT/default
- zfs mount -a 2>/dev/null # home datasets etc.; ignore failures
- #+end_src
-- [ ] Push a full fresh backup to truenas over the LAN — mirror the layout
- the backup job uses (etc + home), into a clearly-named one-off dir:
- #+begin_src sh
- rsync -aHAX --info=progress2 /mnt/etc /mnt/home \
- truenas:/mnt/vault/backups/velox/pre-reinstall-2026-08-13/
- #+end_src
- (=/usr= is in the regular backups but is all reinstallable — skip unless
- paranoid. The 96GB-RAM board will not be the bottleneck; the LAN is.)
-- [ ] Spot-check the copy landed: =wolf.conf.gpg=, =.ssh=, =.gnupg=, newest
- files in =~/documents= and =~/downloads=.
-- [ ] Check for uncommitted repo work and either push or note it:
- =~/.emacs.d= (known: the auto-dim-other-buffers.el unresolved merge),
- =~/.dotfiles=, anything under =~/code=.
-- [ ] Export cleanly: =cd /; zfs unmount -a; zpool export zroot=.
-
-* Phase 3 — Install (the actual DR test)
-
-- [ ] Review the profile, then run the installer:
- #+begin_src sh
- less /root/velox-zfs.conf # FILESYSTEM=zfs, HOSTNAME=velox, single nvme
- archangel --config-file /root/velox-zfs.conf
- #+end_src
- Note: the profile's ZFS_PASSPHRASE / ROOT_PASSWORD are the =welcome=
- placeholders — fine for install; both change post-install (=zfs change-key
- zroot= for the pool, =passwd= for root).
-- [ ] Record every rough edge as a DR-test finding — that's the point of
- running it this way. Anything that needs a manual nudge gets a todo entry
- in archangel or archsetup afterward.
-- [ ] Reboot into ZBM → boot the new environment.
-
-* Phase 4 — archsetup (first boot of the installed system)
-
-- [ ] Log in as root, network up, then verify the clock synced.
-- [ ] Get archsetup — two paths, test the offline one since this is a DR
- drill (the online curl path is the everyday alternative):
- #+begin_src sh
- # offline: mount the install USB and copy the baked tree
- mount /dev/disk/by-label/ARCHANGEL* /mnt 2>/dev/null || mount /dev/sdX1 /mnt
- cp -r /mnt/code/archsetup /root/archsetup && cd /root/archsetup
- ./archsetup
- #+end_src
-- [ ] Expected on the new board: =install_cpu_microcode= detects
- AuthenticAMD and installs amd-ucode (verified 2026-08-13, 7/7 tests).
- Podman socket, camera udev rule, tlp radio state, ZFS /tmp mask are all
- in the installer now — none need manual application afterward.
-- [ ] archsetup clones + stows dotfiles. The velox host tier has no Intel
- assumptions (swept 2026-08-13); maint's capability probe runtime-detects
- amd-pstate.
-
-* Phase 5 — Post-install restore + verification
-
-- [ ] Restore from backup (credentials, ssh keys, gpg, user data). The
- secrets-bundle-in-ISO design is not built yet — manual restore is the
- known gap, not a test failure.
-- [ ] WireGuard: decrypt + re-place =wolf.conf.gpg= at =~/.config/wireguard/=;
- re-import the NM profile (autoconnect off, as before).
-- [ ] Change the placeholder passwords: =passwd=, =zfs change-key zroot=.
-- [ ] PSR workaround — REQUIRED on this board. The Ryzen AI 300 has a known
- idle instability (Panel Self Refresh hangs/reboots the machine; hit during
- the live session 2026-08-13). Add =amdgpu.dcdebugmask=0x610= to the
- installed system's kernel command line — velox boots via ZBM, so set it on
- the pool: =zfs set org.zfsbootmenu:commandline="... amdgpu.dcdebugmask=0x610" zroot/ROOT/default=
- (keep the existing args; append). Revisit after a BIOS update ≥3.05 or a
- kernel that fixes PSR on Strix Point — track via the Framework issue
- tracker (SoftwareFirmwareIssueTracker #110).
-- [ ] New-hardware spot-checks:
- - =journalctl -k | grep -i microcode= — amd-ucode applied.
- - =cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_driver= — expect
- amd-pstate(-epp).
- - wifi + bluetooth up (new board radios), touchpad behavior, camera.
- - =glxinfo -B= / =vulkaninfo --summary= — Radeon 890M on RADV.
-- [ ] Fresh clones automatically carry the post-purge rewritten git history —
- closes the clone-reconcile rider from 2026-08-11 without action.
-- [ ] Fix and verify the backup timer on the fresh install — it was silently
- broken since ~Jul 6. After the first manual run succeeds, confirm a new
- DAILY.0 appears under =truenas:/mnt/vault/backups/velox/=. Diagnose why it
- broke (timer unit dead? mount failure? credential?) if the old journal
- survives in the salvage copy.
-- [ ] Update the machine-identity memory: velox is now AMD (amd-pstate),
- both daily drivers AMD. Fix the stale =intel_pstate= comment in
- =airplane-mode= line 6 while at it (cosmetic).
-- [ ] File every DR-test finding in the owning project's todo.
-
-* Timing
-
-Today is Thursday; the flight is Sunday. Target: Phases 0–4 tonight or
-Friday, leaving Saturday as pure buffer. If the install stalls past Friday
-evening, cut losses to the manual-install floor.
diff --git a/working/velox-reinstall/velox-uefi-boot-entry-reference.org b/working/velox-reinstall/velox-uefi-boot-entry-reference.org
deleted file mode 100644
index 53e6511..0000000
--- a/working/velox-reinstall/velox-uefi-boot-entry-reference.org
+++ /dev/null
@@ -1,108 +0,0 @@
-#+TITLE: Velox UEFI Boot Entry — Recovery Reference
-#+AUTHOR: Craig Jennings
-#+DATE: 2026-08-15
-
-Captured 2026-08-15 before a BIOS update (03.05 → 04.02) as insurance against
-the update clearing NVRAM. Velox's mainboard swap on 2026-08-13 left exactly
-this kind of empty NVRAM, which is what forced the reinstall — so a cleared
-boot entry is the specific failure worth being able to undo in one command
-rather than reconstruct.
-
-* Before recreating anything: check Secure Boot first
-
-The 04.02 update landed on 2026-09-12 (staged via fwupd, flashed on the next
-reboot). It did NOT clear NVRAM: Boot0001 survived with its command line
-intact. What it did was re-enable Secure Boot (Enforce Secure Boot =
-Enabled), so the unsigned ZBM loader was rejected and the Framework BIOS
-reported it as "Default Boot Device Missing / no bootable drive" rather than
-a security violation. The symptom is indistinguishable from the NVRAM wipe
-this document was written for.
-
-The tell: booting the Ventoy stick shows shim's MOK management screen.
-
-Fix: F2 → Security → Secure Boot → Enforce Secure Boot = Disabled, F10. The
-machine then boots straight into ZBM. No efibootmgr needed.
-
-So when velox says no bootable device after a firmware update, check Secure
-Boot before touching the boot entries. Only if Secure Boot is already off
-and =efibootmgr -v= (from the stick) shows Boot0001 gone does the recreate
-below apply.
-
-Before any future firmware update, record both =efibootmgr -v= and the
-Secure Boot state so the post-reboot diagnosis is a comparison, not a guess.
-The pre-firmware-update checklist in
-[[file:../../docs/workflows/system-health-check.org][docs/workflows/system-health-check.org]]
-(Phase 3) carries the steps.
-
-Still open: velox's ESP has no removable-media fallback (=/efi/EFI/BOOT=
-does not exist), so a real NVRAM wipe would still need the stick. Copying
-=zfsbootmenu.efi= to =/efi/EFI/BOOT/BOOTX64.EFI= would let it boot unaided.
-That belongs to archangel's ZBM install, where it is filed as [#C]
-"Installed systems have no removable-media boot fallback on the ESP"
-(2026-09-12) and ships with the next ISO rebuild after it lands.
-
-* State at capture
-
-- BIOS: 03.05 (2025-10-30)
-- BootCurrent: 0001
-- BootOrder: 2001,0001,2002,2003 (USB ahead of ZBM — why the Ventoy stick
- boots when it's inserted)
-- Timeout: 0 seconds
-
-* The entry that matters
-
-=Boot0001* ZFSBootMenu=
-
-| field | value |
-|----------------+----------------------------------------------|
-| ESP part GUID | 8e51b680-f90a-444f-8da5-7e4f93625775 |
-|----------------+----------------------------------------------|
-| partition | 1 (GPT), start 0x800, size 0x100000 |
-|----------------+----------------------------------------------|
-| loader path | =\EFI\ZBM\zfsbootmenu.efi= |
-|----------------+----------------------------------------------|
-| cmdline (data) | =spl_hostid=0x22f8a7a1 zbm.timeout=3= |
-| | =zbm.prefer=zroot zbm.import_policy=hostid= |
-|----------------+----------------------------------------------|
-
-The =data= field is that command line in UTF-16LE, which is how efibootmgr
-passes it as optional data. Recreate with =-u= and the plain string; efibootmgr
-does the encoding.
-
-* Recreating it
-
-From a booted system (or the archangel ISO), with the ESP identified as
-=/dev/nvme0n1p1= or whatever it enumerates as:
-
-#+begin_src bash
-efibootmgr --create \
- --disk /dev/nvme0n1 --part 1 \
- --label "ZFSBootMenu" \
- --loader '\EFI\ZBM\zfsbootmenu.efi' \
- --unicode 'spl_hostid=0x22f8a7a1 zbm.timeout=3 zbm.prefer=zroot zbm.import_policy=hostid'
-#+end_src
-
-Confirm the disk/part against =lsblk -o NAME,PARTUUID,PARTTYPENAME= first —
-the partition GUID above is the authoritative identifier, not the device name,
-which can enumerate differently.
-
-Then set the order so ZBM is reachable:
-
-#+begin_src bash
-efibootmgr --bootorder 0001,2001,2002,2003
-#+end_src
-
-(The original order put USB first. Keep whichever you prefer; what matters is
-that the ZBM entry exists and is in the list.)
-
-* Other entries (firmware-generated, recreate themselves)
-
-| Boot2001 | EFI USB Device |
-|----------+----------------|
-| Boot2002 | EFI DVD/CDROM |
-|----------+----------------|
-| Boot2003 | EFI Network |
-|----------+----------------|
-
-These are stock firmware entries and come back on their own. Only Boot0001
-carries anything unique.
diff --git a/working/velox-reinstall/wttrin-bf0457f.bundle b/working/velox-reinstall/wttrin-bf0457f.bundle
deleted file mode 100644
index 5921866..0000000
--- a/working/velox-reinstall/wttrin-bf0457f.bundle
+++ /dev/null
Binary files differ