8 Commits
Author SHA1 Message Date
wesandClaude Opus 5 de620bfaac Stage the ACannons browser build at /cannons
A third instance of the pattern notebooks-export/ and the reading payloads
already use: an artifact built somewhere with a toolchain this repo's
node:24-slim container does not have, dropped into a gitignored directory,
staged into public/ by a script, and picked up by auto-build.sh's signature on
the next tick. Nothing here needs a JDK, Go, or an opinion about the game --
cannons_reloaded's deploy/export-cannons.sh hands over a directory that is
already ready to serve.

Three things are load-bearing and easy to get wrong later:

The payload is at /cn/, not /cannons/. With build.format:'file' the page
builds to cannons.html, and try_files would then have a file and a directory
competing for the same URL. That is exactly why the notebook exports live at
/nb/ and not under /notebooks/.

nginx gets gzip_static for /cn/. nginx:alpine has `gzip on` commented out in
its base config, so without it the page ships 9MB instead of 3.3MB and nothing
anywhere reports that. It gets no-cache rather than an expiry, because
classes.js and cannons.wasm are stable filenames whose contents change on
every rebuild -- a long expiry would pair a stale client with a fresh server.

The page loads on click, not `loading="lazy"`. Lazy only defers until the
frame nears the viewport and this frame is above the fold, so a few MB would
download for anyone who opened the page to read the paragraph.

A missing export is a normal state throughout: copy-cannons.mjs stages
nothing, the page says so, and the sidebar link does not appear.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01S4wdbGSVzvUDHBWRjSVxfr
2026-08-28 21:17:00 -04:00
wesandClaude Opus 5 d3d93a982a reading map: seven models, one library — /reading/models
The same 9,194 passages arranged by seven embedding models, switchable. Every
model's coordinates are Procrustes-aligned to nomic, without which the toggle
would be seven unrelated arrangements and the motion between them meaningless.

⚠️ The page states the NEIGHBOUR-AGREEMENT number, not the animation, and the
distinction is load-bearing. Every projection of 1024 dimensions into 3 is lossy
in a way that shapes what you see: measured directly, PCA and UMAP disagreed by
10x about whether whole books move together, each reporting its own arithmetic.
So the claim is computed on the raw embeddings where there is no projection to
be an artifact of (models share ~50% of each passage's 15 nearest neighbours),
and the picture illustrates that number rather than being the evidence for it.
The page says so in as many words.

Renderer gains setCoordinates(), driven from the existing render loop rather
than its own rAF so a morph cannot outlive the scene or run while scrolled away.
It writes through the single `xyz` buffer the nebula, signal and trace all read
from, so every layer moves together and nothing drifts out of registration.

`trace` is now optional. The banner and explorer always carry one; a comparison
payload legitimately does not — its subject is where passages MOVE between
models, not the order they were highlighted in.

Payload is split: a 44 KB manifest with everything shared, plus one ~145 KB
coordinate file per model fetched on demand. The per-node book/kind arrays are
identical across models, so carrying them seven times is waste, and eager
loading would be ~1.1 MB before first paint.

auto-build.sh now watches public/reading_*.json as ONE glob. The previous
OR-chain was subtly broken — with `-o` the `-printf` binds only to the last
clause, so earlier matches printed in a different format and the signature was
not stable. The glob also picks up future payloads without an edit.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-16 13:40:11 -04:00
wesandClaude Opus 5 898c942f95 reading map: a second page, arranged to be read rather than to look like weather
The banner draws all 9,194 chunks in one flat colour. `nodes.book` was in the
payload but only ever reached the tooltip, so nothing on screen said which book
or which region you were looking at.

This adds /reading: the same corpus at the pre-flight's 15/0.1 instead of the
banner's 50/0.8, coloured by kind of book, with any single title isolatable.

The two projections are NOT interchangeable, and that is why this is a separate
page rather than a mode of the banner. 50/0.8 was chosen *because* it blurs book
territory into something that reads as a cloud; showing that territory is the one
thing this page exists to do.

Renderer notes:

  • Explorer mode turns on only when the payload actually carries a `kind`
    layer, not when the caller asks for it — a page pointed at the banner's
    file degrades to the flat cloud instead of throwing.
  • Smaller and denser points (0.032/0.62 vs 0.055/0.3). Three hues piling up
    in one volume average toward grey; that pairing is what keeps each one's
    hue, and it is not cosmetic.
  • Isolation dims to 8.5% rather than hiding. Against an empty frame you learn
    where a book's chunks are and lose the only question worth asking, which is
    where they sit relative to everything else.
  • `nebulaBase` keeps a pristine copy of the vertex colours; dimming from an
    already-dimmed buffer compounds and the cloud would fade on every hover.

Kind colours are slots 1-3 of the validated categorical palette, checked
ALL-PAIRS against this file's own #0b0d12 — a point cloud has no series order,
so the adjacent-pairs default that suits stacks and lines is the wrong test.
Worst pair CVD dE 9.4, worst normal-vision dE 20.9.

⚠️ `--map-kind-narrative` (aqua) sits near `--map-trace` (the garden green).
Tolerable only because form separates them absolutely — diffuse points versus
one continuous line — and nothing is encoded by the similarity. If the trace
ever becomes points, re-measure that pair.

The payload is gitignored for the same reason the banner's is: a tracked
generated file dirties the tree and breaks the `git pull` at the top of every
build tick. auto-build.sh's signature now watches both, or a corpus change
would rebuild one page and leave the other on yesterday's cloud.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-15 20:42:14 -04:00
wes d0f56e4881 Reading map: the payload is a generated artifact, not a tracked file
library-rag-export.service now regenerates reading_umap.json on cyrion
whenever the corpus or its located highlights move, writing straight into this
checkout. Keeping it tracked would defeat that: a generated file that changes
under git dirties the tree, which both flips auto-build.sh's change signature
and breaks the `git pull` at the top of every build tick — the reason
notebooks-export/ is already ignored, in that file's own words.

So it joins them: ignored, plus a find line in the signature block so the
5-minute tick still notices a new projection.

The cost is that a fresh checkout has no map until the service runs — on
cyrion that is within the hour, anywhere else never. ReadingMap.astro says so
where someone would hit it.
2026-08-14 07:59:25 -04:00
wesandClaude Opus 5 9da9a6cba2 Publish opted-in marimo notebooks at /notebooks
Notebooks from the marimo server can now appear in the garden. A notebook
opts in with an HTML comment in one of its markdown cells — invisible when
rendered, greppable in the .py source:

    <!-- garden:publish
    title: Dream of Spotification
    order: 30
    -->

Default-deny on purpose: garden.c0smere.net is public and the export bakes
each notebook's executed output into the page, not just its code.
export-notebooks.py also carries a NEVER_PUBLISH list (genome_*, coursework)
so a marker pasted into one of those refuses loudly instead of publishing.

Pipeline: export-notebooks.py runs each marked notebook in a one-shot
marimo container (same image/env/GPU as the live server, so it hits the real
databases) into notebooks-export/ + index.json; copy-notebooks.mjs stages
those to public/nb/; Astro reads index.json to build the pages and the
sidebar section.

Isolation choices worth keeping:

- Own timer and own lock, separate from the 5-min garden build — executing a
  notebook takes minutes and must never hold up a build tick.
- Cached on notebook content; both index.json and .cache.json go through
  write_if_changed, since auto-build.sh hashes mtimes under notebooks-export/
  and an unconditional rewrite would force a full rebuild every 30 minutes.
- Per-notebook timeout; a failure keeps the previous export and continues.
- Runs against a throwaway copy of the notebook dir, so notebooks that write
  scratch files don't dirty the notebooks repo.
- Notebooks are NOT injected into the garden collection — they aren't vault
  notes, and doing so would move noteCount and the sitemap.

build.format:'file' makes the listing a file (notebooks.html) beside a
directory of detail pages. Verified against the running nginx: /notebooks and
/notebooks/<slug> resolve through the generic try_files but /notebooks/ does
not, so nginx.conf gets an explicit location for the trailing-slash form.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-29 22:07:14 -04:00
wesandClaude Fable 5 3d70e23471 Manual rebuild hook + polish: single title h1, '›' tree marker
- deploy/rebuild-hook.py: tiny stdlib HTTP service (:18101) — button
  page for the Homepage dashboard iframe, POST /rebuild runs
  auto-build.sh --force, /status + /healthz for feedback/monitoring
- auto-build.sh: --force flag + flock so timer and manual builds
  serialize
- [...slug].astro: skip the synthetic h1 when the note body already
  opens with an identical h1

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-21 21:45:36 -04:00
wesandClaude Opus 4.8 b31ea9fc82 Production cutover: rename container to garden, add auto-rebuild timer
- deploy/auto-build.sh: git pull + rebuild only when the repo HEAD or any
  vault file mtime changed (sha256 signature in .build_state); replaces
  the Quartz update_quartz_docker.sh loop
- systemd user units (5-min cadence, matching the old Quartz timer)
- compose service/container renamed garden-next -> garden

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-15 15:51:42 -04:00
wesandClaude Opus 4.8 04c9aa2fb2 Astro garden skeleton: Quartz-compatible URLs, Obsidian markdown, odometer homepage
- glob content loader over the vault's Digital_Garden with verbatim-path ids
- remark plugin: wikilinks, image embeds (wiki + relative md), callouts
- URL parity with live Quartz sitemap verified 102/102 (built set is a
  strict superset: +30 synthetic folder listings)
- KaTeX, lazy mermaid, shiki dual themes, quoted-string draft handling
- copy-assets resolves embeds vault-wide (fixes live-site 404s for
  Blog Scratch/assets images) into flat /assets/
- homepage odometer widget: fetches api.c0smere.net baseline, ticks at
  lifetime average rate, fail-closed hidden on error
- deploy/: nginx try_files config + compose (port 18100) + containerized
  build script for cyrion

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-15 14:18:59 -04:00