Commit Graph

90 Commits

Author SHA1 Message Date
Levi Neuwirth 1f1969ab28
vita: generate the project index, and add a web_visible axis
The project index was the last hand-maintained duplicate of CV data, and it
had already drifted: a superseded Weenix line count and an end date the CV
disagreed with. It now renders from yaml-source/data/projects.yml, which
grows from three entries to nine and gains `group` (drives the index's
sections, first-appearance order, like now.yaml) and `links`.

Pmacs, Levshell, and Epiphany join under "Personal" — self-directed tools
rather than coursework or employment — written from the repos rather than
from memory. They are web-only: personal infrastructure is not academic
output, and the résumé is a full page. LeVCS keeps its essay; project
writeups stay essays, since a writeup is an informal presentation of a
project and not a record of it.

web_visible is a third visibility axis alongside cv_visible and
resume_visible, defaulting to cv_visible so nothing changes until it is
set. The file already knew how to let the CV and résumé disagree about an
entry; generating a third surface from the same data would otherwise have
collapsed that, and a document handed to a chosen reader is not a page that
gets crawled. This is what makes web-only projects expressible — and what
would let the xAI entry sit quietly on the CV while staying off the site,
if that is wanted later. It stays off both for now.

Two LaTeX conversions added while moving the markdown prose into the YAML:
$\rightarrow$ and $\sim$. The latter fixes a bug I introduced doing it —
"~10 crates" meant "about ten", but bare ~ is LaTeX's non-breaking space,
so it rendered "( 10 crates" and dropped the approximation.

Weenix's description now carries the site's fuller tail (the CS 169 origin
and the later pipes/preemption work) rather than the CV's terser "Brown CS
169." Single-sourcing means picking one, and this is the better one; the CV
grows by a clause and the résumé still fits on one page.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SUGesXiMmACsLBTGG1xuEU
2026-08-11 09:07:38 +02:00
Levi Neuwirth 29c4b80a2a
vita: generate /about from the CV data instead of hand-copying it
The vita page carried a hand-typed duplicate of education, publications,
presentations, and experience, and had drifted from the PDFs in about
fifteen places — Shu Lab still one entry titled "Undergraduate
Researcher" three months after the degree, Weenix at ~7,000 lines, CHASE
still "accepted" after being presented, a preprint missing entirely, and
two different code URLs for the same paper.

build/Vita.hs reads yaml-source/data/*.yml — the same files the PDF
pipeline builds from — and renders education, experience (keeping the
CV's research/industry split), publications, presentations, and contact.
Drift is now structurally impossible rather than merely discouraged.

Notes on the implementation:

- The YAML is LaTeX-flavoured because xelatex is its first consumer, so
  values pass through a small closed converter (\textbf, \textit,
  \texttt, \href, $\times$, $\delta$, \#, {,}, ~, --, ---). Escaping
  happens before conversion; unhandled commands pass through visibly
  rather than silently dropping their argument.
- Scalars are parsed loosely: the same logical field is sometimes a YAML
  number and sometimes a string (`year: 2026` vs `year: "2026--2027"`),
  and the PDF pipeline does not care, so this does not force it to.
- personal.yml's phone number is deliberately not read. It is printed on
  the CV, which is handed to a chosen reader; this page is crawled.
- Contact chips carry labels (ORCID, Forgejo, GitHub) rather than the
  CV's full display values, which exist because paper cannot be clicked.

The page keeps only what nothing else on the site owns: the pointers and
the four research threads. In-progress work belongs to /current, the
engineering index to /cv/projects/, and the narrative to /me/ — whose
abstract already described this page as the formal record.

vita.css composes on item-card.css and mirrors now.css's headings and
chip geometry, so /about and /current read as one system. Link chips get
the only interaction polish on the page, being the one affordance a
printed CV cannot offer.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SUGesXiMmACsLBTGG1xuEU
2026-08-11 08:40:33 +02:00
Levi Neuwirth d4031a79f2
cv: August 2026 refresh across CV, résumé, and site
Dated facts:
- CCV affiliation ended July 2026; drop the "(HPC-supported)" role suffix
  and the Phase 2/3 in-progress claim (also on the résumé's PQC entry).
- Weenix ended August 2025 at 10,000 lines; the site said ~7,000 and
  January–May 2025.
- CHASE 2026 presented August 3; moved to now.yaml's shipped list and
  marked Presented on the CV.
- Shu Lab split at the degree boundary: Undergraduate Researcher and
  Technical Lead (Oct 2023 – May 2026), then Research Affiliate
  (May 2026 – Present, bulletless — the work is described above it).
- DTU advisor/research-group TBD note removed.

Claims that had started to decay:
- Math preprints read "Preprint" rather than "arXiv (forthcoming)", and
  now.yaml calls them revising rather than in-review.
- SIMD/PQC is paused pending a compute move to DTU.
- Semantic-embeddings work dropped; MTG no longer claims OSCAR.

Redundancy:
- NSF affiliation description reduced to the two qualifications its title
  and role line don't already state; MARS V grant note to the funding
  terms; DTU fellowship placeholder deleted; NeuroAI held to one line.

Structure:
- xAI toggled off on both documents (retained in the file, two flags away).
- Contract work renders inside Industry Experience above NeuroAI as
  "Independent Research Contractor"; Selected Contract Work is now
  conditional so the heading can't render empty.
- Templates: guard bulletless entries, and fix an unguarded exp.location
  in the CV that printed a literal "None" for entries without one.

now.yaml: pmacs, levshell, and epiphany notes rewritten against the actual
repos (all three were badly out of date); epiphany added.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SUGesXiMmACsLBTGG1xuEU
2026-08-10 23:40:14 +02:00
Levi Neuwirth 3a089c3f76
auto: 2026-08-10T20:44:42Z [skip ci] 2026-08-10 22:44:42 +02:00
Levi Neuwirth 458e996399
auto: 2026-08-10T18:17:29Z [skip ci] 2026-08-10 20:17:29 +02:00
Levi Neuwirth 74c1baa525
auto: 2026-08-10T16:23:35Z [skip ci] 2026-08-10 18:23:35 +02:00
Levi Neuwirth cce92577bd
auto: 2026-08-10T16:17:24Z [skip ci] 2026-08-10 18:17:24 +02:00
Levi Neuwirth 1baba7a613
auto: 2026-08-10T16:12:16Z [skip ci] 2026-08-10 18:12:16 +02:00
Levi Neuwirth 6dfa62d7ec
auto: 2026-08-10T15:58:52Z [skip ci] 2026-08-10 17:58:52 +02:00
Levi Neuwirth bdd0c0f321
auto: 2026-08-07T16:37:48Z [skip ci] 2026-08-07 18:37:48 +02:00
Levi Neuwirth cf8573d0ec
auto: 2026-08-05T11:11:26Z [skip ci] 2026-08-05 13:11:26 +02:00
Levi Neuwirth b14ab3089a auto: 2026-07-27T15:57:49Z [skip ci] 2026-07-27 11:57:49 -04:00
Levi Neuwirth 1931970f7d auto: 2026-07-27T15:38:04Z [skip ci] 2026-07-27 11:38:04 -04:00
Levi Neuwirth 78d4adbfc4 auto: 2026-07-25T16:05:34Z [skip ci] 2026-07-25 12:05:34 -04:00
Levi Neuwirth 5fbbb10aed auto: 2026-07-24T18:34:02Z [skip ci] 2026-07-24 14:34:02 -04:00
Levi Neuwirth a81266ad80 auto: 2026-07-24T18:25:12Z [skip ci] 2026-07-24 14:25:12 -04:00
Levi Neuwirth a6c78c1758 auto: 2026-07-23T02:06:31Z [skip ci] 2026-07-22 22:06:31 -04:00
Levi Neuwirth e553d652ae auto: 2026-07-21T13:08:14Z [skip ci] 2026-07-21 09:08:14 -04:00
Levi Neuwirth 86840205ae auto: 2026-07-21T13:04:04Z [skip ci] 2026-07-21 09:04:04 -04:00
Levi Neuwirth 7b69a1d49f auto: 2026-07-18T10:01:53Z [skip ci] 2026-07-18 11:01:53 +01:00
Levi Neuwirth 84f6f2bbff auto: 2026-07-10T16:19:57Z [skip ci] 2026-07-10 12:19:57 -04:00
Levi Neuwirth b856911279 Archive: close out the audit-pass refinements
Six follow-ups from the link-archive audit, all the items with a
code-shaped fix. Behaviour verified per feature (stubbed + live where a
network or browser was needed); ARCHIVE.md status notes updated alongside.

- suggest: `archive.py suggest` + `make archive-suggest` print works
  cited in data/*.bib (url wins, DOI-only resolves to doi.org/...) but
  absent from the manifest, as manifest-ready lines. Read-only, offline.

- aliases: optional `aliases:` manifest field for equivalent URLs no
  normalisation can derive (DOI vs. landing URL). Enforced like canonical
  URLs on both sides (archive.py pre-scan + Archive.hs validator);
  ArchiveIndex drops alias keys matching a takedown. FIPS 203 now carries
  its DOI form, so the simd paper's DOI citation resolves.

- check scheduling: systemd user timer (systemd/archive-check.{service,
  timer}, symlink-installed) runs the rot scan daily. cmd_check gains an
  offline canary guard so an unattended scan on an offline machine leaves
  state untouched instead of mass-flipping entries to rotted.

- Wayback fallback: an original already dead at first fetch falls back to
  its most recent existing Wayback capture (raw id_ bytes through the
  normal pipeline), honouring a preserved X-Archive-Orig noarchive and
  recording `fetched-from`. Dead-only, never during refresh.

- bibliography annotation: Filters.Archive exports annotateBlock;
  Citations.hs applies it to each CSL-rendered entry, so bibliography
  links get the same affordance / rotted-flip as body links.

- search-UI filter: archive "exclude/only" + "link status" filters on the
  search page, backed by a new data/archive-meta.json. Scoped apart from
  the epistemic `status` filter (own state, classes, labels) rather than
  renamed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-19 16:23:14 -04:00
Levi Neuwirth 9f61ce5949 Tooling, manifest, and content polish
- import-photo.sh deletes the copied JPEG when EXIF stripping fails, so
  the auto-commit can never publish GPS/serial metadata (AUDIT §4.11)
- pre-commit-marks hook: tab-aware path parsing, probes the staged blob
  rather than the working tree (§4.11)
- preset-signing-passphrase uses printf; stamp-build-time writes via
  temp + os.replace; archive.py passes -- to pdftotext and verifies the
  vendored monolith binary against its recorded sha256 (mismatch is
  fatal, consistent with the tool's integrity contract); extract-exif
  ./-prefixes relative paths (§4.11)
- blog-post.html: id="similar-links"/"backlinks" each appear once;
  rendered output unchanged (§6.4)
- site.webmanifest: start_url/scope/description added, maskable icon
  purpose restored alongside any (§9.3)
- Frontmatter cleanup: scaffold comments out of scaling_outage,
  dangling null confidence-history keys removed (populated ones kept),
  dead modified: key dropped from colophon (§6.4)
- canto31.jpg: 4.0 MB -> 1.9 MB (2400px, q80, grayscale — the source
  is a monochrome Doré engraving, so single-channel is colorimetrically
  lossless); webp sidecar regenerated (§6.4, prior-audit §6.1)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 11:13:34 -04:00
Levi Neuwirth aeb2937f7c Drafts are local-only: untrack the four committed ones
.gitignore has declared content/drafts/ local-only working notes since
the rule was added, but four drafts were already tracked — ignore rules
don't untrack, so make build's auto-commit kept staging and deploy kept
pushing them (AUDIT §6.3). Untracked with --cached; the files remain on
disk and still build in dev. Also moved inclusionist-manifesto.md into
drafts/essays/ where the draft rule actually matches it (§6.1), and
un-shadowed the tracked .env.example from the credential patterns.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 10:40:05 -04:00
Levi Neuwirth 4e28c82e4c Fix SIMD essay repository URL: add missing owner segment
https://git.levineuwirth.org/where-simd-helps returned 404; the
owner-qualified form returns 200 (AUDIT §6.2).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-10 09:44:26 -04:00
Levi Neuwirth 620b974d3f auto: 2026-05-26T15:50:02Z [skip ci] 2026-05-26 11:50:02 -04:00
Levi Neuwirth 14c881b9e4 auto: 2026-05-16T23:42:26Z [skip ci] 2026-05-16 19:42:26 -04:00
Levi Neuwirth e61a9e495c auto: 2026-05-16T23:28:47Z [skip ci] 2026-05-16 19:28:47 -04:00
Levi Neuwirth 711912cdfb auto: 2026-05-16T23:20:57Z [skip ci] 2026-05-16 19:20:57 -04:00
Levi Neuwirth 36748573cd auto: 2026-05-09T01:05:52Z [skip ci] 2026-05-08 21:05:52 -04:00
Levi Neuwirth 670d477cd6 auto: 2026-05-06T16:35:22Z [skip ci] 2026-05-06 12:35:22 -04:00
Levi Neuwirth be6aca9214 auto: 2026-05-06T16:29:30Z [skip ci] 2026-05-06 12:29:30 -04:00
Levi Neuwirth 998e4a9b51 auto: 2026-05-06T16:09:51Z [skip ci] 2026-05-06 12:09:51 -04:00
Levi Neuwirth e4cf152066 auto: 2026-05-05T17:23:31Z [skip ci] 2026-05-05 13:23:31 -04:00
Levi Neuwirth 22b530c26d auto: 2026-05-03T16:57:50Z [skip ci] 2026-05-03 12:57:50 -04:00
Levi Neuwirth f41311a3eb Inline code reference previews 2026-05-02 10:40:43 -04:00
Levi Neuwirth b12f6cc387 auto: 2026-05-02T13:07:26Z [skip ci] 2026-05-02 09:07:26 -04:00
Levi Neuwirth 0fc9fec708 auto: 2026-05-02T12:45:20Z [skip ci] 2026-05-02 08:45:20 -04:00
Levi Neuwirth cd94227acb Spec dilemma 2026-05-01 21:22:01 -04:00
Levi Neuwirth 3a5326d92d auto: 2026-05-01T16:17:51Z [skip ci] 2026-05-01 12:17:51 -04:00
Levi Neuwirth 968b810394 auto: 2026-05-01T15:47:38Z [skip ci] 2026-05-01 11:47:38 -04:00
Levi Neuwirth 04e4aff641 auto: 2026-04-29T01:17:30Z [skip ci] 2026-04-28 21:17:30 -04:00
Levi Neuwirth 1c856cd6f8 auto: 2026-04-27T18:46:44Z [skip ci] 2026-04-27 14:46:44 -04:00
Levi Neuwirth 53e053e9a7 auto: 2026-04-26T23:24:06Z [skip ci] 2026-04-26 19:24:06 -04:00
Levi Neuwirth 5cb6795a7a auto: 2026-04-26T20:47:12Z [skip ci] 2026-04-26 16:47:12 -04:00
Levi Neuwirth 370f81217c auto: 2026-04-26T15:31:49Z [skip ci] 2026-04-26 11:31:49 -04:00
Levi Neuwirth 6585573dae States/Context/Embeddings fixes 2026-04-26 11:22:57 -04:00
Levi Neuwirth 40ba09209c Professional content refactor 2 2026-04-22 11:56:25 -04:00
Levi Neuwirth 913a374fb2 Professional content refactor 2026-04-22 11:46:57 -04:00
Levi Neuwirth e969461ca3 auto: 2026-04-21T02:24:58Z 2026-04-20 22:24:58 -04:00