Godstrument/GODSIGH_CROSSOVER_BRIEF.md
2026-07-13 13:34:18 +10:00

10 KiB
Raw Permalink Blame History

GODSIGH ✕ GODSTRUMENT — Crossover Build Brief

Audience: Claude Opus 4.8, executing autonomously in this repo (godstrument). Author: Claude Fable 5, 2026-07-13, after mapping both codebases. Companion: ~/Documents/GODSIGH/SPEC2.md (the sibling wave in the GODSIGH repo). Task 3 below shares a cache contract with it — the contract text must stay in sync.

Before anything: skim README.md, run.py (worker supervision + profiles), one worker (workers/world_iss.py is the cleanest contract example), config.json (signals/routes/groups shape), and the Spirits shelf region of viz/index.html (~line 5111 on, "one Source, many Spirits, one Matter"). Match house style: workers are argparse + pythonosc standalone processes emitting /gs/<group>/<name>; commits carry an emoji prefix (🛰, 🥁, 📖…); shipped features get a grimoire/manual entry (see the 📖 commits and GODSTRUMENT_MANUAL_SOURCE.md); *_BRIEF.md files are deploy-excluded. Verify in the browser (python3 run.py --profile minimal + your new worker) before each commit.

Execute the four tasks in order; commit + push per task.


Task 1 — 🎹 Land the local "keyroll" work (groove editor) safely

Situation. Branch local/groove-editor (commit c0c3a98, single commit on top of pre-godrum 3ff105d) holds ~637 lines of real local work on the sequencer: a piano-roll editor with draggable note lengths (.seqnote overlay blocks with an ew-resize handle), velocity + chance lanes (.explane draggable bar-per-step lanes), a seqedit wrapper with lane toggles/selectors, Euclidean tools (.euc, .tnum), groove knobs (.aknob), bar-line markers, and a scroll container. Meanwhile main merged the whole godrum line, which reworked the same sequencer UI area and independently built per-step velocity+chance, Euclidean fills, swing/humanize, and Follow Actions.

Do NOT git merge local/groove-editor blind — the branches rewrote the same regions and an auto-merge will produce soup. Instead:

  1. Feature-gap analysis first. Read the branch diff (git diff 3ff105d..local/groove-editor -- viz/index.html) and the current main sequencer ("Groove" region, ~viz/index.html:202/:238, plus godrum's beat panel). Build an explicit table: for each keyroll feature — note lengths / velocity lane / chance lane / lane toggles / euclid tools / groove knobs / bar lines / scroll container / big-grid variant — does current main already have an equivalent (however differently spelled)?
  2. Port only the gaps, natively. Reimplement each missing feature on top of current main's structures and naming (the branch is the reference spec, not a patch to apply). Likeliest genuine gaps, from marker analysis: the note-length piano roll (seqnote spanning blocks with drag-resize — main has none) and possibly the explane-style aligned drag-lanes UI; likeliest already-covered: euclid, velocity/chance data (godrum has the data model — the gap may be only the lane editor UI).
  3. Keep godrum's behavior intact — its choke anchors, euclid guard, kick-duck etc. were carefully review-hardened (fa5aa43, b0fad08); regressions there are worse than missing a keyroll nicety.
  4. Verify by playing: place notes with lengths, drag velocities/chances, euclid-fill, confirm godrum voices still behave, MIDI export still valid.
  5. When everything valuable is landed on main, delete the branch (git branch -D local/groove-editor) and say so in the commit body — that branch is the only copy of the reference work, so delete it only after the port is committed and pushed.
  6. Grimoire/manual entry for the new editor capabilities, per house convention.

Task 2 — 🛰 workers/world_sats.py: real satellites as a source (SGP4, no polling APIs)

GODSIGH proved the pattern: TLEs from Celestrak + SGP4 gives any satellite's position locally at any rate — no per-fix HTTP like world_iss.py needs. Bring that superpower here as a worker:

  • Dependency: sgp4 (pure-python, pip). Add to requirements.txt.
  • TLEs: fetch at startup from https://celestrak.org/NORAD/elements/gp.php?GROUP=stations&FORMAT=tle plus NAME=GAOFEN&FORMAT=tle and NAME=COSMOS%202486 / NAME=COSMOS%202506 (the recon birds — thematic gold). Cache the TLE text to ~/.cache/godverse/tles.txt and refresh only if the cache is >24 h old (Celestrak politeness; TLEs age slowly). Tolerate fetch failure by using a stale cache; tolerate no-cache-no-net by exiting politely like other workers.
  • Compute (default --interval 2): propagate each satrec to now (sgp4 gives ECI; convert to lat/lon/alt via the standard GMST rotation — port the math from GODSIGH js/layers/satellites.js / satellite.js's eciToGeodetic, it's ~15 lines), then derive elevation angle above the venue city's horizon (city lat/lon from cities.json via the same --lat/--lon retargeting run.py applies to other geo workers — accept those flags).
  • Emit (the contract: raw floats, hub normalizes):
    • /gs/sats/best_elev — highest elevation (degrees, can be negative) among tracked sats: the "something is overhead" continuous signal.
    • /gs/sats/overhead_count — count with elevation > 10°.
    • /gs/sats/iss_lat, /gs/sats/iss_lon — keep the ISS sweep available even when world_iss.py isn't running.
    • /gs/sats/pass.event — impulse when any sat crosses rising 30° (a recon bird crests the sky and a bell rings). Include which sat in the printed log line.
    • /gs/sats/recon_elev — best elevation among only the GAOFEN/COSMOS set (the watchers' own channel).
  • config.json: declare the new signals with sensible norm ranges (elev lo:-30, hi:90; count lo:0, hi:8) + labels; add 23 starter routes (suggest: sats.best_elev → pad.brightness gentle; sats.pass → delay.feedback impulse; sats.recon_elev → lfo.rate — the sky watching back). Add the worker to the WORLD profile in run.py.
  • Grimoire/manual entry: "the sky's schedule joins the orchestra."

Task 3 — 🤝 Shared OpenSky cache (reader side)

The contract (mirrored verbatim in GODSIGH SPEC2.md §4 — keep in sync):

OpenSky shared cache v1. Path: ~/.cache/godverse/opensky-states.json, overridable via env OPENSKY_CACHE_FILE. Content: the raw, unmodified OpenSky /states/all JSON response body (global, no bbox). Writer: whoever successfully fetches from upstream writes the body atomically (write to <path>.tmp in the same directory, then os.replace). Freshness = file mtime. Readers treat the cache as fresh if mtime is within 120 s; on upstream 429/failure, readers may serve/use a stale cache rather than nothing.

GODSIGH's dev proxy implements the writer side. Here, make workers/world_planes.py cache-aware:

  1. Each poll cycle: if the cache file exists and is fresh, read it and skip the HTTP call entirely (log [world_planes] cache hit). GODSIGH fetches globally; if this worker uses a bbox, filter the cached global states client-side by lat/lon — same fields, indices 5/6.
  2. On a real HTTP poll that succeeds with a global scope, write the cache per the contract (atomic tmp+rename, mkdir -p the directory). If this worker polls a bbox, do NOT write (never write partial data into a global-contract file).
  3. On 429 or network failure: fall back to a stale cache if present (log it), else current behavior.
  4. Keep the existing ≥450 s cadence — the cache makes the effective shared cost whatever the most aggressive consumer pays, once, per window.

Result: GODSIGH (90 s cadence) + godstrument running together spend ~one poller's quota instead of two.

Task 4 — 👁 "GOD'S EYE" Spirit (a skin for the shelf)

A new Spirit in the existing shelf system (register exactly like the others — bagua ~:5791, Kandinsky ~:5689 are good templates): the world's sensor picture as the cosmology. 2D canvas, house style — no new libraries.

  • Stage: a minimal equirectangular world (a sparse hand-drawn continent outline is enough — store a small [[lon,lat],...] polyline set inline; do NOT ship a heavy geo dataset into the one-file viz), graticule every 30°, dark ground, the venue city marked with a ring.
  • Seat the feeds geographically, not symbolically (this Spirit's whole cosmology is literal coordinates): quakes flash at their true lat/lon (the quake worker's events carry location — check what reaches the WS feed and use what's available; if only intensity arrives, flash at the venue antipode and note it), ISS/satellites sweep as moving points with short trails (from Task 2's sats.* lat/lon signals), planes as a shimmer band whose brightness = planes.count-ish signal, market as a ticker pulse at the financial capitals (NY/London/Tokyo dots), solar wind as an aurora wash at the poles, wiki edits as brief sparks at random civilizational coordinates.
  • Tuning: like every Spirit, choose a scale + palette identity — suggest a cold surveillance palette (near-black, cyan #35e0ff, warning amber) and a minor-pentatonic retune, so entering the Spirit sounds like a watch floor.
  • Register it on the shelf, respect performance mode (P) and zen (Z), grimoire/manual entry ("the eye that hears").

Verification & workflow

  • Per task: run python3 run.py --profile minimal plus the touched worker(s) with explicit flags; watch the hub log for your signals arriving; open the viz and confirm in the browser (Spirit renders, sequencer plays, no console errors). python3 -m py_compile every touched .py; keep workers import-safe when optional deps are missing (house rule).
  • Commit per task with the emoji house style; push after each. End commit messages with Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>.
  • Do not deploy anything from this brief; deployment of godstrument follows its own conventions and is not part of this work.

Pitfalls

  • Task 1: the keyroll branch predates godrum — never trust an auto-merge; port by intent. Delete the reference branch only after the port is pushed.
  • sgp4's Satrec.sgp4() returns position in km, TEME frame — the GMST rotation to geodetic is mandatory, and satrec.no_kozai is rad/min (mirror GODSIGH's math, it's verified).
  • Celestrak NAME queries can return No GP data found plain text — detect (first data line must start with 1) and treat as empty, not fatal (verified behavior, same as GODSIGH).
  • Atomic cache writes: keep the .tmp beside the target file (same filesystem), not in /tmp.
  • The viz is one 9,256-line file — make surgical, well-commented insertions in the established regions; don't reorganize it.