PML mixins carry across; the PML disclaimer becomes expandable - #133
Merged
Conversation
…andable Mixins were the documented-impossible half of PML compatibility. The impossibility argument rules out TRANSLATING a PML splice into a TSPML AST mixin, or faking the live function it patches — it does not rule out running PML's patch language at TSPML's own patch time. The #62 request-carried plan already goes from "a mod's declared patches" to "the served bundle"; a splice is just another patch riding it. Pipeline: shim COLLECTS object-spec registerClassMixin calls (the form real CDN mods ship — ghosttoggle 1.0.8 is the reference) per call, refusing everything it cannot faithfully apply (method-extent types, wasm offsets, the other seven families keep their named refusals). The page persists collected specs onto the record (JSON-key dedupe) and re-parks the plan WITHOUT reloading the mod — the mod is already running; only the plan changed. user-patches carries pmlMixins with the same caps as injects (func). At the route, splices edit the RAW bundle text BEFORE Babel — PML tokens are written in Kodub's own minified formatting and would not survive regeneration — and the engine's existing re-parse gate covers the spliced source: a broken splice boots vanilla, never corrupted (observed live). The rule that makes it TSPML's: an anchor must match exactly once or the patch refuses with the count — plus the one concession measurement forced: twin anchors (tokenStart === tokenEnd, what ghosttoggle actually ships) occur ONCE in the real bundle, so a single occurrence is legal (empty span, insert after); two splice between; three refuse. smoke:pml now proves both halves in a browser: OVERRIDE + registerGlobalMixin refused by name while the mod stays loaded; a real splice whose token exists exactly once in vanilla 0.6.2 and runs at bundle eval is collected-and-not-run on the first boot, then EXECUTED in the game frame after one reload with the in-bundle report reading applied:1 on main.bundle.js. UI: the PML install caveat is a native <details> — one line, the paragraph behind an expander. The filter row split into labelled groups (loader / category / people) per owner note, each keeping the tag-row class so every existing locator still sees the same control. Portal 695 -> 722 tests (pml-splice.test.ts new at 18); repo-wide 1,335 green; smoke typecheck run AFTER the last script edit this time.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
roowus
added a commit
that referenced
this pull request
Aug 28, 2026
* fix(portal): the PML Core / PML API rows answer 'do I need this?' on the card Both rows now say outright what the adapter means for them: TSPML supplies the PML runtime itself, so neither is required — install only if a mod asks by name (nothing in the catalog does). The pmlapi summary also dropped a stale clause claiming mixins 'cannot carry across'; token-anchored ones have since #133. * feat(portal): game versions become the fourth derived tag group Owner: "also add version numbers to the tag". Fourth application of the derivation rule (format, persons, no-build prose, versions): everything a card states about itself is computed from the row's own fields. The chip is the versions the row COVERS, not the gameVersions list: computed with buildsForGameVersion against a universe (every release version in the catalog + the launcher default, newest first). Chipping the literal range string would have made the 0.6.2 filter falsely drop poly-to-track, the one native mod — pinned by unit test and smoke:registry leg 2d (chip narrows to exactly the eight covering rows, range entry among them; the inverse of the thirteen-warned assertion, one predicate). Prereleases are excluded from the universe — a beta chip answers nobody's filter question; the detail facts row still shows the full list. The filter and the chips agree by construction: searchRegistry derives its own universe from the entries in scope, the grid passes the tab's, the detail page the registry's. Monospace (.tag-version) is the only visual signature. Portal 722 -> 728 tests (registry.test.ts 80 -> 86); repo-wide 1,341 green; smoke typecheck after the last script edit; smoke:registry PASS with the new leg; screenshot review done (four labelled rows: loader/category/version/people).
roowus
added a commit
that referenced
this pull request
Aug 29, 2026
Owner's diagnostic log: "4 mods 1 tspml works 3 pml dont" — three mods, three refusals, three real call shapes the collector had never met. All three mods' sources were fetched from the CDN and read; all three now carry. - 3decspeed refused as "no type" because its spec's type IS a type — a NUMBER. PML's real MixinType (PolyTypes.js, read from the CDN) is a numeric enum (INSERT=3, REPLACEBETWEEN=5), and every mod importing PolyTypes.js by its absolute CDN URL — all of them — puts that number in the spec. The parser is now bilingual: names and numbers, mapped from the real enum. - husplits' registerFuncMixin(name, spec) and noitalics' registerGlobalMixin(spec) were refused BY FAMILY. Family is PML's targeting hint — it decides where PML looks — and the exactly-once token rule subsumes looking. Every source-op family collects now; what still refuses, by name: method-extent values (0/1/2), class-wide values (4/7/8, they apply at every site at once), the two wasm families, and calls with no spec object. The re-run exposed a trap in the fixture itself: in comma-expression context a bare parenthesized func PARSES as a call of the preceding call's result — it sets its marker, then throws, truncating the game's boot tail after the marker. #133's "passing" splice was almost certainly doing exactly that while green. The discipline (now in the fixture's comments): leading comma in comma-sequence context, semicolon-statement in block context. And the numeric splice's first token was lazy-path code (verifier catch) — applied but never ran; a marker proves execution only where the token's site executes at bundle eval. The fixture now pins: string enum, numeric enum, lone-object global twin-anchor — 3/3 applied in the browser, both markers firing in the game frame. Three catalog summaries that said these mods' mixins "are refused and reported" now say they carry after one restart. Portal 728 -> 734 tests; repo-wide 1,347 green; smoke typecheck after the last script edit.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Owner: "the pml disclainmer should be expandable, also can u make mixins carry over to". Two features — one UI, one that reverses the most-repeated claim in the PML compatibility docs.
1. Mixins carry across
The docs said PML mixins were not translatable in general — sound, as far as it went: you cannot rewrite a token-splice into an AST mixin, and there is no live function left to patch by the time a mod's
initruns. The third option nobody had taken: run PML's patch language at TSPML's own patch time. The #62 plan already carries declared patches to the served bundle; a splice rides it.lib/pml/shim.ts): object-specregisterClassMixin(the form real CDN mods ship) parsed per call; the four token-anchored types (INSERT/REPLACE/REPLACEBETWEEN/REMOVEBETWEEN) are collected. Method-extent types, wasm offsets, and the other seven families keep their named per-call refusals.app/play/page.tsx): after a load summary, collected specs merge onto the record (JSON-key dedupe) and the plan re-parks — deliberately WITHOUT the mod-reload path; the mod is running, only the plan changed.lib/user-patches.ts):pmlMixinsjoin pasted mixins, one set per mod,funccapped exactly asinject.lib/pml/splice.ts+demo-transform.ts): token surgery on the RAW bundle before Babel (PML tokens are written in Kodub's own minified formatting and would not survive regeneration), under an exactly-once anchor rule — ambiguous matches refuse with the count. The engine's existing re-parse gate covers the spliced source; a broken splice boots vanilla (observed live:planStatus: base-failed, game fine).tokenStart === tokenEnd, ghosttoggle's real shape) occur once in the real bundle — so one occurrence is legal (empty span, insert after it), two splice between, three refuse. The first draft of the rule would have refused ghosttoggle's actual mixin.Player-visible consequence, stated at install and in the Mods panel: mixins apply on the NEXT launch — first boot collects and says so, the reload applies. Same shape as physics plans, for the same reason (plans park before the frame's first fetch).
2. Expandable disclaimer + grouped filters
<details>: one line, full reasoning behind an expander.tag-rowso existing smoke locators are untouched.Proof
smoke:pmlPASS end-to-end, both halves: refusals by name with the mod still loaded; a real splice (token = the game's own FPS-counter keybind registration, exactly-once in vanilla 0.6.2, executes at bundle eval) is collected-and-not-run on boot 1, then executed in the game frame after one reload, with the in-bundle report readingapplied: 1.base-failed→ vanilla boot, never corrupted.pml-splice.test.tsnew, shim collection block, splice composition, plan carriage); repo-wide 1,335 green;tsc+ smoke typecheck clean — the typecheck run AFTER the last script edit this time.Docs (same merge)
docs/concepts/pml-compatibility.mdrewritten ("Mixins: carried, with PML's semantics and TSPML's discipline" replaces "Why mixins cannot be translated"; the carries table, Files, and Proved-in-browser sections updated),docs/project/progress.mdnew section, README bullet + count.