1. 07 Jun, 2026 29 commits
    • docs(tasks): archive 42 completed board tasks pre-compact · 070a86d0
      Snapshot resolved tasks (foundation/distro, Ardour/boundaries, Judge UI, triangle
      DRY, fleet colour, the sample-grounding fun-sprint, and the dataviz epic #64) so
      the active board stays lean. Active board now = pending/in-progress only.
      PLN (Algolia) authored
    • feat(unwrapped): de-mud the field + zoom/pan to dive in · 8a61a415
      Field: per-cell DOMINANT family colour (was a mean of all overlapping hues →
      brown mud); mixed/overlap zones now fade by 'purity' instead of muddying.
      Tuned colourful-but-subtle behind the dots (desaturate 0.40 + slight lift to
      white, maxα 0.44) — dots stay the stars.
      Zoom/pan: wheel to zoom at cursor, drag to pan when zoomed, +/−/reset controls
      (top-left) + double-click reset; dots grow with zoom; field & hit-testing follow
      the view transform, clipped to the plot rect.
      PLN (Algolia) authored
    • data(resolve): ground all 1485 corpus samples — fill the per-folder gap · d69e0aa0
      sample_families.json was built at a smaller per-folder cap → only 831 per-index
      entries (825 of the 1485 plotted samples labelled). Re-ran the resolver at
      --max-files 12 (same clap:fine method) over 150 folders → 1501 per-index entries,
      1490 labelled. unwrapped.json now 100% family-coloured (was ~56%): no more grey
      'unlabelled' dots, the density field reads everywhere.
      PLN (Algolia) authored
    • feat(unwrapped): density colour-field behind the scatter (timbral regions) · 1729689b
      Low-res IDW of dot colours (72x46 Gaussian-weighted, σ≈3.1), desaturated 50% and
      faded by local density, bilinear-upscaled behind the dots → pink kick region,
      blue keys region, purple bass / yellow hat pockets emerge as a slow gradient.
      Cached offscreen, rebuilt only when colours/axes/filter change (never on hover);
      'regions' toggle in the controls; auto-off in vibe-search mode.
      PLN (Algolia) authored
    • fix(vibe): warm-up runs a real text forward (absorb torch lazy-init) · cec9dec3
      Loading weights wasn't enough — the first forward still cost ~30s on torch's
      one-time graph/thread init. Warm now runs a throwaway _embed_texts() so the first
      USER query is ~1.5s, not 30s.
      PLN (Algolia) authored
    • fix(vibe): warm CLAP at server startup + honest UI feedback/timeout · e3b1fecc
      The first /vibe hit cold-loaded CLAP (~16s) with the UI stuck on 'searching…',
      reading as hung. Now serve.py warms the model in a daemon thread at startup (when
      semantics_embeds.npz is present) so the first query is instant; the client shows
      'first search loads the model, ~15s' on a cold start and aborts after 90s with a
      retry hint instead of spinning forever.
      PLN (Algolia) authored
    • feat(landing): dataviz front door + honest style cloud (#63,#88) · c122e7a5
      index.html ties the corpus dataviz together (By the numbers · Unwrapped · The
      Triangle) and opens with a typographic style cloud sized by TRACK count — read
      from PLN's own gig metadata (catalog_view metas[].style via models.norm_style),
      never per-sample CLAP genre. dnb 18 · breaks 17 · techno 14 · nujazz 12 = the
      TechnoJazz spine. build_landing.py bakes landing.json (cloud + corpus stats).
      Ship's Bridge; magenta only on the live-dot + cloud hover.
      PLN (Algolia) authored
    • feat(unwrapped): seeded vibe-search + find-similar + semantic vibe-map (#82,#87) · 6351e0ae
      - build_unwrapped: 2D PCA of the CLAP embeds → per-sample 'vibe map' coords +
        16 seed-vibe chips (PLN's own words — the on-ramp, since users don't know what
        to type). vibe0/vibe1 join the axis picker as a semantic-space lens.
      - unwrapped.html: VIBE SEARCH box (free text → /vibe) + clickable seed chips;
        results highlight on the map (dim misses, size hits by similarity, ring the top,
        faint-violet→magenta ramp) and auto-reveal the vibe map; result strip auditions.
        Shift-click any dot → /similar (nearest neighbours in embedding space). Null-safe
        plotting for vibe/raw axes. Graceful banner when the endpoint is absent.
      PLN (Algolia) authored
    • feat(semantics): validated CLAP vibe-search + live /vibe endpoint (#82,#86) · ac4643d0
      Katana-first finding: per-one-shot CLAP genre/mood tags are unreliable (every
      hit → boom-bap/euphoric — a 0.3s sound has no genre), but the audio EMBEDDINGS
      are gold for RELATIVE similarity. 'warm dusty rhodes' → suns_keys gold-keys +
      west-coast electric; 'jazzy upright bass' → no_sunshine/come_bass loops; a kick's
      nearest neighbours are other kicks (0.96 cross-folder). So we ship similarity,
      not fake absolute labels (Principle 1: trust the instrument).
      
      - sample_semantics.py validated on real audio; semantics_embeds.npz = 1490×512-d.
      - serve.py: lazy CLAP /vibe?q= (embed any phrase → rank) + /similar?name= (by
        audio-embed cosine). 503 if unbuilt, 400/404 on bad input; static serving
        untouched. Single-user LAN, torch loads once on first hit.
      PLN (Algolia) authored
    • feat(unwrapped): explorable feature-space map of the sample corpus (#81) · b7adc89e
      ParVagues Unwrapped — a Ship's Bridge dark explorable over unwrapped.json:
      - The map: canvas scatter of all 1,485 samples; pick any 2 of the 5 named
        superfeature axes (or raw features); colour by family / audio-cluster /
        folder-kind / folder-agreement; hover to identify, CLICK TO AUDITION the .wav.
      - The five axes: PCA loading bars (what composes each superfeature) + RF
        family-discriminator importances (centroid + temporal-centroid on top).
      - Family fingerprints: per-family beeswarm on a switchable feature — the
        kick-punchy / bass-sustained split made visible.
      - Folders are loose: family x audio-cluster contingency grid (ARI 0.25) — the
        timbre-not-label story, the data behind 'a folder is a loose grouping'.
      Zero npm deps; fleet family colours; magenta reserved for the audition pulse.
      PLN (Algolia) authored
    • feat(unwrapped): bake explorable per-sample feature dataset (#81) · c2d6eedb
      Joins per-file features × resolver family/kind × standardized PCA projection
      (PC1-5) × KMeans timbral cluster × audition .wav path into one unwrapped.json
      the browser explores without recomputing. Reuses feature_eda.load_matrix so the
      matrix matches the MDA exactly. Names the 5 leading PCs as superfeature axes
      (Brightness / Timbre / Loudness / Envelope kick-bass / Tonal-noisy), orienting
      coords by a stable anchor so poles read right. Contract tests green.
      PLN (Algolia) authored
    • fix(resolve): a folder is loose — kits read as kits, not a 'dominant' verdict · 9134398c
      PLN: each SAMPLE is classified individually; a folder is a loose grouping, often a
      heterogeneous KIT. Added kind=single|dominant|kit; for kits folder_agrees=None and
      the run shows KIT [fam+fam] not a misleading dominant+flag. Folder-name flag now fires
      only for folders claiming ~one family (cpluck->synth still flagged). Regenerated palette.
      PLN (Algolia) authored
    • feat(feature_eda): MDA over 1485 samples → the superfeature axes · 01b88ed5
      sample_features.py overfetched 36 L0/L1 features × 1485 corpus samples; feature_eda
      mines them three ways:
      - correlation: only 2 redundant pairs ≥0.9 (duration~temporal_centroid 0.97,
        bandwidth~rolloff 0.91) → the overfetch was lean, 34/36 independent.
      - PCA: intrinsic dim 19 (90%) / 24 (95%) — genuinely high-D. The 5 leading PCs are
        interpretable SUPERFEATURE AXES: PC1 brightness (rolloff/centroid), PC2 timbre
        (mfcc5-8), PC3 loudness (rms/peak/flux), PC4 envelope/time (temporal_centroid,
        decay_slope, attack — the kickbass axis), PC5 tonal-vs-noisy (kurtosis/chroma_entropy).
      - clustering: KMeans(12) vs resolver families ARI=0.25 NMI=0.40 (timbral clusters
        partly orthogonal to semantic family — consistent with 'folders are loose').
        RF importance: spectral_centroid + temporal_centroid are the #1/#2 family
        discriminators → validates productizing the kickbass tiebreaker (#80).
      TDD: 3 synthetic invariants (redundancy/dim/separation) + real-data load guard.
      PLN (Algolia) authored
    • data(step1): grounded sample palette — 149 corpus folders (clap:fine) · a93c47af
      Layered resolver (L1 filename -> L3 batched CLAP audio -> L2 folder cross-check).
      116 homogeneous, 33 kit-like, 20 folder-name disagreements flagged (cpluck->synth,
      amencutup->snare, sunny_brass->pad, nujazz_keys125->lead...) — audio overrides the
      name, flags surface for review not silent override. max_files=6, ~7min.
      PLN (Algolia) authored
    • perf(clap): encode the text tower once, audio-only forward per folder · 96854679
      The ~88 fine descriptors were re-encoded through RoBERTa on every folder's
      forward — a fixed cost that made batch size irrelevant. Now cache the normalized
      text embeddings + logit scale at load; per-folder forwards run only the audio
      tower (get_audio_features) and a matmul against the cached text embeds. ~1.8x
      (14s->7.7s/folder; text was ~45% of per-folder cost).
      
      API note (transformers 5.10.2): get_text/audio_features return a model-output
      object whose .pooler_output IS the projected 512-d joint embedding — verified
      identical to a full ClapModel forward to 1.6e-7. No classification change.
      PLN (Algolia) authored
    • feat(resolve): --max-files knob to trade CLAP cost vs kit per-index detail · 3250dcbb
      Opaque folders send every file through a batched HTSAT forward; --max-files N
      caps that. Defaults to CLF.MAX_FILES (12). Use 6 for fast dominant-family
      grounding when full per-index kit detail isn't needed.
      PLN (Algolia) authored
    • data(eda): ground all 61 local takes (Stage-1 corner-B coverage) · 04cbf307
      Per-take per-orbit level/register/activity from local Ardour interchange stems
      via the optimized build_eda. 61/61 grounded (~8min, warm cache 12-19s on the
      big SET takes). 2 empties correctly flagged (Take28 0.6s, Take63 8.6s sketches);
      kick orbit (d1) sub-register on all 57 active (centroid never >300Hz).
      PLN (Algolia) authored
    • perf(resolve): batch the resolver's audio path into one CLAP forward/folder · c32db821
      resolve_folder looped classify_file per file -> one CLAP forward per opaque
      file. Now: run L1 (filename) for all files first, then classify ONLY the opaque
      ones in a single batched forward. Extracted classify_files() as the one place
      per-file audio prediction lives (CLAP batched, PANNs per-file); classify_file
      and classify_folder both route through it so batching can't be lost by accident.
      Validated on the jazz kit (per-index BD/HH/SN via filename, CB/P1/P2 via audio).
      PLN (Algolia) authored
    • perf(build_eda): L-only single-decode + thread-parallel orbits · 16937a78
      The cost is the ffmpeg read (LUKS-decrypt + WAV parse), not the FFT or pipe
      (astats-only emit was no faster). Decode the L channel only — stereo orbit
      stems share the activity envelope, and that single full-SR decode now serves
      both the 2s-bin envelope and the loudest-window spectral profile. Orbits decode
      concurrently in a bounded thread pool (ffmpeg releases the GIL). 78-min SET take:
      96s->57s; further gains hit the disk I/O wall (~190MB/s), not CPU. Low-SR was
      rejected (anti-alias lowpass kills hat brilliance + mislocates the loud window).
      PLN (Algolia) authored
    • fix(catalog_view): fail loud when site content (corner C) is missing · f8b7b41e
      build_catalog_view silently returned 0 tracks when www is on a branch without
      next/content/lives (the redesign branch) — which would let tide.py build clobber the
      good catalog_view.json with an empty one. Now raises a clear error; IT fixtures skip
      cleanly when the external site dep is unavailable. Suite: 49 passed, 17 skipped.
      PLN (Algolia) authored
    • feat(sample_features): librosa overfetch extractor + TDD on real samples · 0f0331ac
      ~35-feature vector (Peeters/CUIDADO timbre + MIR), convol-inspired L0→L1 tier tags.
      Validated kickbass discriminators on real samples (temporal_centroid + decay_slope):
      bd 0.064s/-165dB/s vs fbass 2.30s/-11dB/s. 5 invariant tests green.
      PLN (Algolia) authored
    • feat(build_eda): per-take EDA emitter + TakeEDA/OrbitEDA/EDAStatus models · 9731a386
      Measures level/register/time-activity per orbit from local Ardour stems → eda_{take}.json
      (silent/empty flags); ledger scans interchange → eda_status.json. Finding: 61 takes
      locally reachable (not the 9 assumed) → most of the catalog groundable offline.
      PLN (Algolia) authored
    • feat(sample-resolve): layered family resolver → grounded sample_families.json · 3ce8bba8
      L1 filename (sample_meta) → L3 audio fallback (sample_classify ensemble-fine, the
      73% scoreboard winner) → L2 folder cross-check (flags folder_agrees=False when the
      folder name lies). Audio runs ONLY on opaque files. Per folder: dominant, agreement
      conf, homogeneous, kit_like, per-:index labels with source, provenance. Validates
      the domain knowledge mechanically: jazz=kit (000_BD→kick :0, HH/OH→hat, SN→snare),
      cpluck=multisample (plucks+body, folder='keys' flagged), 808hc=perc via audio.
      PLN (Algolia) authored
    • feat(presence): typed online-presence SSOT (profiles + per-release links) · bdfdf5fc
      The site hardcodes platform URLs across 7+ components; this consolidates them into
      one typed source. models.py: Platform/LinkKind/ReleaseKind enums + PresenceLink,
      ReleaseTrack, Release, Presence. presence.authored.yaml = verified inventory (6
      profiles, 4 releases, 18 links) with provenance; build_presence.py validates →
      presence.json and stamps default file-provenance. Wired into tide.py build +
      generated TS (Presence interface) so the site can later consume it — one-directional,
      opt-in (site keeps owning editorial gig content). Per-track links modelled as a
      capability, populated only where a real direct URL exists. 61 tests green.
      PLN (Algolia) authored
    • fix(classifier): drop bare startswith — 2-char cues must not prefix-match · 9f15bee8
      The unguarded s.startswith(m) let 2-char cues overreach: cp→cpluck→snare,
      808→808hc→bass. It was redundant (the ≥3-char token-prefix clause already covers
      single-token plurals like pads→pad). Removed it: short cues now fire only as exact
      name/token. cpluck→keys (its string identity, not snare); 808hc/808mc→None and
      defer to audio (CLAP hears conga). Regression tests added. Full suite 61 green.
      PLN (Algolia) authored
    • feat(sample-meta): L1 filename-metadata harvester (free per-file signal) · 521127ff
      RIFF chunk dump proved samples carry NO semantic embedded metadata (only encoder
      tags) — the Pulsar browser shows FILENAMES. So harvest the filename: leading pad
      index + instrument-token lexicon → fleet family + source hint. Conservative: opaque
      names (JUPI, doing_it_right, 808hc's 'HC') stay family=None → fall back to audio.
      Detects kit-like folders (≥2 families by name), the 'jazz is a kit' case.
      Corpus coverage: 49% folders / 31% files named, 36 kit-like folders.
      PLN (Algolia) authored
    • perf(sample-classify): batch CLAP per folder + parallel decode + progress · acf6a7c1
      One forward pass per folder (text tower computed once) instead of per-file —
      ~Nx fewer forwards; ffmpeg decode on a thread pool. validate prints a live
      [i/N] running-accuracy line. source field now reflects method:mode.
      PLN (Algolia) authored
  2. 06 Jun, 2026 11 commits
    • feat(sample-classify): fine ontology + PANNs + ensemble methods · bb70f394
      Per PLN: richer ontology + PANNs/AudioSet + ensembles for sample grounding.
      - sample_ontology.py: 99 fine descriptors across the 12 families ('this is the
        sound of {a reese bass}'); scored per-descriptor then marginalized to family.
        CLAP fine: 58% -> 68% top-1 (coarse super-family 76%) vs the noisy name truth.
      - sample_panns.py: PANNs Cnn14 (AudioSet 527) -> conservative label->family map ->
        per-family prob vector. ffmpeg @32k, zero-pad short one-shots (Cnn14 needs >=1s
        of mel frames or conv5 collapses). Weak on electronic one-shots (AudioSet
        'Clapping'=applause, not a drum-machine clap).
      - sample_classify.py: --method clap|panns|ensemble, --fine|--coarse. clap_vector()
        exposes the family-prob vector; ensemble = mean of CLAP+PANNs vectors -> argmax.
      
      Scoreboard (vs name-heuristic, itself noisy): clap-coarse 58% | clap-fine 68% |
      panns - | ensemble - (head-to-head primed, not yet run). Stubborn residual =
      bass<->kick one-shot (spectral decay tiebreaker is the next lever).
      PLN (Algolia) authored
    • feat(sample-classify): CLAP zero-shot sample-family analyzer (katana) · 3e14a623
      Ground sample families by LISTENING, not by name. sample_classify.py runs
      laion/clap-htsat-unfused (transformers, torch CPU) over Dirt-Samples one-shots,
      scoring each against text prompts for the 12 fleet families; aggregates per folder
      (dominant + homogeneity → kits show as mixed). ffmpeg audio I/O, no librosa.
      validate/run/one commands; validate measures top-1 vs the name-confident folders.
      
      Finding (validate): 58% top-1 agreement with the name-heuristic at fine 12-way.
      KEY: the name 'ground truth' itself is wrong in many disagreements — CLAP correctly
      calls 808hc/808mc congas (perc), which the name-classifier mislabeled bass via '808'.
      CLAP is near-perfect on vox/break/clear-bass/kick/keys; the genuinely fuzzy zone is
      the melodic cluster (synth/lead/keys/pad). Prompt-tuning is whack-a-mole on noisy
      truth. Conclusion: trust CLAP coarsely, not at fine 12-way silently.
      PLN (Algolia) authored
    • fix(classifier): refuse to guess kits + source-named folders; fix sept1 morpher · e9bba22c
      PLN-flagged chain of labeling errors, traced to the SSOT classifier:
      - 'jazz' was matched to BREAK, but jazz is a multisample KIT (jazz:0=kick,
        :1=snare/hat…). A folder name is not a reliable family signal: it may be one
        family, a heterogeneous kit, or a demucs grab named after a SOURCE song
        (wap, take5, the_revolution, xplosive, rample*). classify_sample_family now
        fires ONLY on names that lexically encode an instrument; everything else is
        None (= needs per-sample analysis). No 'kit registry' (that's name-guessing too).
      - removed over-reaching genre/source tokens: jazz, dnb, jungle, loop from break;
        drum from perc. This also FIXES jungle_pads (→pad, was break) and
        jungle_vocals (→vox). amen kept (amencutup genuinely is the Amen break).
      - tempo: strip Tidal '--' line comments before parsing cps (ton_numero's
        commented-out morpher no longer counts); a track with a live 'cps (range …)'
        is now flagged morph even when it also declares a fixed setcps. morphing=1
        (Septembre 1er, 60→180), was 0.
      - report: + stage_tempo_by_year, sources/roadmap, recurrence gig_slugs,
        classified/unclassified coverage (21% of palette uses need analysis, honest).
      - tests: classifier refuses kit/source names; jungle_pads→pad guard. 60 green.
      PLN (Algolia) authored
    • feat(corpus-viz): hover tooltips + all-dots collab view + copy de-slop · 3f2863d4
      PLN review pass:
      - tooltip layer: hover any mark for the tracks/examples behind it. cloud dots
        (track + bpm + date), tempo line dots (median + what it means), histogram
        bands, gig/sample columns, family segments (count + % + example members),
        idiom bars (plain-language gloss of each phrase), staple bars, collab dots
      - collab story now plots EVERY track as a dot; tracks at the same BPM pile into
        one larger dot (radius ~ count); median drawn as a tick; sample-tell chips get
        lift tooltips. needs tide_eda collab_fingerprint to emit per-track {name,bpm}
      - copy: removed cheap 'not X, Y' contrasts + em dashes per impeccable clarify;
        added 'hover anything' affordance hints
      PLN (Algolia) authored
    • feat(corpus-viz): 'by the numbers' scrollytelling dataviz (task #64) · 33d49591
      Phase-2 infodesign of the tide_eda corpus EDA: a standalone, scroll-driven
      data essay (corpus.html) on the Ship's Bridge dark instrument language.
      
      Six curated stories, vanilla SVG (zero npm deps), measured-width responsive:
      1. the slow climb — studio vs club tempo, dual median lines + track cloud +
         histogram + felt-vs-written 2x inset; studio<->club lens is first-class
      2. 2024 breakout — vocab burst + gig cadence on a shared time axis, magenta
         reserved for the one earned 2024 accent
      3. palette — 12 sample families as a proportion bar, fleet colors + glyphs
      4. the accent — signature gMask/gMute idioms (f*16 in 62/73)
      5. collab fingerprint — per-collab bpm range + distinctive samples (raph fast)
      6. set-staples — recurrence, Cafe trilogy highlighted
      
      - tide_eda: add stage_tempo_by_year (gig-date x track-tempo) for the club lens
      - build_corpus.py + 'tide.py corpus': inline-bundle to one self-contained file
        for deploy to me.nech.pl/parvagues/viz (dist/ gitignored)
      - IntersectionObserver reveal/lazy-draw, reduced-motion + mobile reflow,
        load-fail banner; lens auto-disables on single-lens sections (honest)
      - 59 tests green
      PLN (Algolia) authored
    • docs(corpus-viz): confirmed design brief + implementation spec (task #64) · 830d2dd1
      Phase-2 infodesign brief from /impeccable shape: standalone scrollytelling
      'ParVagues, by the numbers', 6 curated stories on the fleet color language,
      studio<->club toggle as first-class lens, vanilla SVG no-deps, deploy static
      to me.nech.pl/parvagues/viz. Exact eda_report.json field->chart map for a
      clean post-compact build.
      PLN (Algolia) authored
    • feat(backlog_setlists v2): explicit ends, label-strip, leet fallback + tests · 9a428b6e
      - ANCHORS support (slug, end_line) to bound bleeders (mephisteuf/opal-2025/
        38c3-toilet) into clean blocks — no more swallowing neighbour setlists.
      - clean_track_line: strip leading set-position labels (Intro:/Finale:/Sunset),
        keep 'Label: Name' / drop 'Name: gloss'; recovers the LIVE-Noctambule pattern.
      - leet_fold fallback (B00K→book, T01l3ts→toilets, G00D→good) — resolves only
        after a straight miss so genuine digits (sept1) still match first.
      - 9 gap gigs recovered (opal-2024 14/14, algolia-fdlm 26/26, 39c3 13/14…).
      - 6 mechanical tests (leet, label, gloss, bpm/transition, ascii/comment skip,
        real-backlog coverage guard). 59 pass.
      PLN (Algolia) authored
    • fix(eda holes): canonical sample classifier + style normalization · 21d003dd
      - models.py: add classify_sample_family() SSOT (token-aware, DM-suffix gated,
        strong-contains fallback) + extend SAMPLE_FAMILIES cues → unclassified 89→34
        uses (~93% classified); honest unknowns (armora, 90s_matrix) stay None.
      - models.py: STYLE_ALIASES + norm_style() merges nu-jazz/nujazz, breaks/breakbeat,
        chip/chiptune, hip-hop/hip so the style chart is honest.
      - tide_eda + tests use the canonical classifier (DRY); +3 mechanical tests
        (token cases, no-overreach incl. the shil-'oh' FP, style norm). 53 pass.
      - regen tokens (cues feed match[] arrays).
      PLN (Algolia) authored
    • feat(tide_eda): phase-1 EDA over the corpus (tempo, collab, pairings, time) · f7132e2d
      Reusable data-scientist pass that finds the stories before any viz:
      - TRUE tempo parsed from setcps (corner A), vs metadata bpm (C), with AC delta
        (most conflicts are exact 2× half-time/double-time notation, not errors)
      - studio tempo (git-creation date) vs stage tempo (gig date) — the creep 110→126
      - collab fingerprint: bpm profile + lift-distinctive samples per collaborator
        (raph outed as the fast/club one ~138bpm; nova-solo ~117)
      - sample pairings: lift-ranked co-occurrence, ad-hoc 'pair <prefix>' query
      - cadence (all 37 canonical gigs), sample-family split, signature idioms,
        set-staples, vocabulary growth (Dirt-Samples symlink mtime, 334-pack Jul'24 burst)
      Emits eda_report.json (tidy cuts for the viz phase).
      PLN (Algolia) authored
    • feat(backlog_setlists): recover gig setlists from backlog.md → resolved .tidal · 5acf72f7
      The site tracks.json covers only 23/37 gigs; the rest live in backlog.md as
      codename-keyed setlist blocks. New mechanical parser cleans the noisy lines
      (ASCII-art, emoji, emphasis, inline [bpm]/{transition} notes, commented-out
      tracks) and resolves names to canonical .tidal paths via the catalog's own
      alias index (DRY). Gig-codename→slug mapping is authored (confirm:-flagged
      when uncertain); suspect_bleed flags blocks that swallowed a neighbour list.
      6 gigs cleanly recovered (52 track-slots); seam is larger (dozens of setlists).
      PLN (Algolia) authored
    • fleet color language + triangle UX redesign (impeccable pass) · 6815967f
      ontology in models (SSOT) → generated tokens:
      - models.py: OntologyTerm + ColorFamily; ROLE/LIFECYCLE/AGREE terms (color+glyph+
        label) and an authored 12-family SAMPLE-WORLD model (hue-anchored). Variation =
        OKLCH lightness ladder + ±8° hue-fan → 8 shades/family = 96 sample slots. Sample
        axis (conceptual) kept separate from the measured-register axis (ROLE_FAMILIES).
      - tools/gen_tokens.py: OKLCH→sRGB (no deps) → tokens.css (armada/ui) + tokens.json
        (triangle fetches at runtime, overrides :root). Validated vs DesignTokens. New
        tide.py 'tokens' step. Never hue alone (glyph+label per term).
      
      triangle UX (low cognitive load, clear hierarchy):
      - header calm at rest: one title line, one quiet coverage line, and the agreement
        bar is now the interactive sea-state instrument (overview + legend + level filter
        in one) — replaces the duplicated chips+stack+pills.
      - faceted full-text search: free terms + scopes (sample:/gig:/phrase:/take:/style:/
        name:), covers the pattern registry, with 'matched-in' hints so results never feel
        mysterious; '/' focuses, clear button, teaching empty state.
      - sound chips colored by sample family (shared lexical classifier from tokens),
        glyph-paired; agreement painted from the ontology (unparsed no longer red).
      - tests: 51 green (OKLCH math, shade ladder greyscale-distinctness, ontology
        integrity, unparsed≠conflict, DRY tokens contract, classifier examples).
      PLN (Algolia) authored