Skip to content

  • Projects
  • Groups
  • Snippets
  • Help
  • This project
    • Loading...
  • Sign in / Register
T
Tidal
  • Overview
    • Overview
    • Details
    • Activity
    • Cycle Analytics
  • Repository
    • Repository
    • Files
    • Commits
    • Branches
    • Tags
    • Contributors
    • Graph
    • Compare
    • Charts
  • Issues 0
    • Issues 0
    • List
    • Board
    • Labels
    • Milestones
  • Merge Requests 0
    • Merge Requests 0
  • CI / CD
    • CI / CD
    • Pipelines
    • Jobs
    • Schedules
    • Charts
  • Wiki
    • Wiki
  • Snippets
    • Snippets
  • Members
    • Members
  • Collapse sidebar
  • Activity
  • Graph
  • Charts
  • Create a new issue
  • Jobs
  • Commits
  • Issue Boards
  • PLN
  • Tidal
  • Repository

Switch branch/tag
  • Tidal
  • tools
  • pvlint
  • rules.py
Find file
BlameHistoryPermalink
  • PLN (Algolia)'s avatar
    feat(surface): the mutes group by ROLE, the filters by BLOC — two maps, one author (#105) · 72943be9
    PLN settled the gM question on 2026-07-30, and the answer was not the one this task
    had assumed for a day:
    
      "I want the kick, now on d1/fader1, to have its mute on F1 botrow button. I want
       the C1 knob to djf all percs, C2 only bass djf, C3 melodies DJF. however i want
       the mutes consistent across all all tracks: m1 d1 / m2 other percs / m3 all
       bass+melodics"
    
    ## The thing I had wrong
    
    #105 was framed as "align gM<N> to gF<N>" — make the mute index mirror the filter
    index so an orbit's knob and button share a column. I measured 35 mismatches in the
    set under that invariant and was ready to fix them.
    
    That invariant is WRONG, and the measurement was answering the wrong question. The
    filters and the mutes are two different gestures:
    
      FILTERS want the rhythm section as ONE BLOC     — you sweep the drums together
      MUTES want the kick SPLIT OUT on its own button — you drop the kick alone
    
    So gF groups {d1,d2,d3,d8} and gM splits d1 from {d2,d3,d8}. Under the real map the
    edit count is 55, not 35 — and `d4: gF2+gM3`, which the mirror-invariant called a
    mismatch in 11 tracks, is CORRECT. Had I shipped the "alignment" I would have moved
    11 correct lines and left the kick sharing a button with the hats.
    
    Recorded as tools/lcxl_grid.py `_FILTER_FAMILY` / `_MUTE_FAMILY` — in the ONE
    authored grid (#97), with his words above it, so the asymmetry reads as deliberate
    rather than as drift. `as_dict()` now exports `orbit_family` so the HUD can say which
    knob AND which button own an orbit; `--generate` rewrote tools/lcxl_grid.json and the
    HUD package's own copy (outside this repo, in Tools/pulsar-parvagues-hud).
    
    ## tools/fix-mute-roles.py
    
    Convergent migrator: `--apply` rewrites, `--check` exits 1 on drift (a pre-gig gate),
    `--fill` gives a mute to a block that has none, `--report-missing` writes a markdown
    report instead. Reads the map from lcxl_grid rather than restating it.
    
    ## PV012 / PV013, so it cannot re-drift
    
    PV012 flags an orbit whose gM does not match its ROLE — deliberately NOT "gM index
    != gF index", and there is a regression test asserting `d2 $ gF1 $ gM2` is clean,
    because a rule written to the mirror invariant would flag that valid line. PV013
    flags an orbit with no family mute at all: PLN's "no mute is oversight!" — nothing on
    the surface can drop such an orbit, so taking it out means editing live.
    
    ## PV013 immediately caught a bug in the migrator that wrote it
    
    Minutes after PV013 existed, it flagged `d5` in you_my_sunshine — an orbit the
    migrator had walked straight past. Cause: fix-mute-roles had its OWN orbit regex
    requiring `^dN $`, and that file's head line is `d5  -- The Voice of Love`, no `$`,
    with the gates on a commented continuation. pvlint's regex allows `dN` followed by
    `$`, `--`, or EOL. Two parsers disagreeing about what an orbit IS is the same class
    of bug as two copies of the grid, so the migrator now imports pvlint's parser and
    owns none of its own. Re-running found 14 more rewrites and 7 more missing mutes it
    had silently skipped — the miss was under-application, not corruption, but it would
    have left exactly the inconsistency this task exists to remove.
    
    Also fixes #109: the orphan-orbits hand-measurement for you_my_sunshine still
    expected d7, which PLN moved to d6 in ce887b78. Re-derived by reading the file's
    column-0 declarations, not by pasting the parser's output — a hand measurement that
    quotes the thing it checks is a tautology.
    
    Suite: 222 passed, 0 failed (8 new PV012/PV013 tests).
    PLN (Algolia) authored Jul 30, 2026
    72943be9
rules.py 34.8 KB
EditWeb IDE
×

Replace rules.py

Attach a file by drag & drop or click to upload


Cancel
A new branch will be created in your fork and a new merge request will be started.