feat(skills): ship ue-design-skills bundle, licensing and delivery gate

Phase 0 of the handoff plan, as a marketplace rather than a flat skills/
directory. Content moved out of the LyraResearch archive and depersonalised:
addresses stay in the archive, recipes ship.

- plugins/ue-design-skills: 17 skills, 232 failure-mode entries, each with the
  six required fields; catalog.json as the harness-neutral source of truth and
  .claude-plugin/ as one adapter over it.
- _gate: 16 rules, one poisoned fixture per rule, plus surface coverage so a
  declared file cannot silently miss the line rules.
- ADR-0002 (harness-neutral bundle behind a marketplace) and ADR-0003 (split
  licensing: CC BY-ND 4.0 prose, Apache-2.0 code and metadata).
- LICENSE files at both levels, CONTRIBUTING.md, docs/licensing-options.md as
  the material the licence decision grew from.

Verified: gate.py 0 violations; test_gate.py 16/16 rules redden on their
fixtures with a clean baseline and 2 root files reaching the line rules.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-05 23:48:55 +07:00
parent 80ea7b03a9
commit ecd87ac96d
67 changed files with 21630 additions and 0 deletions
@@ -0,0 +1,202 @@
# Patterns: platform budgets in a measured reference product
A worked reading of one shipped platform-budget configuration: scalability
buckets, device profile tiers, streaming pools and the code that applies them.
This file is almost entirely about **configuration**, which makes it unlike the
others in this bundle in one important way: none of the findings below are bugs
in the usual sense. Every value is valid, every file parses, and the game runs.
What the audit produced is a list of places where the configuration says
something the runtime does not do — and the only reason any of it is findable is
that someone read the engine's own configuration alongside the project's.
Markers: **[measured]** — read in project or engine configuration and source;
**[derived]** — conclusion from measured facts; **[open]** — requires hardware.
**No number here is a memory measurement.** Nothing was profiled. Everything is
a declared budget, which is exactly the distinction the skill is about.
---
## 1. The single most useful table in the audit
What the project declares about the texture streaming pool, per mobile tier
**[measured]**:
| Tier | Pool declared by the project | Effective source |
|---|---:|---|
| Low | — | engine scalability bucket |
| **Mid** | **85 MB** | **device profile** |
| High | — | engine scalability bucket |
| Epic | — | engine scalability bucket |
The project sets the pool in exactly two lines — the mid tier of each mobile
platform — and declares **no** per-tier texture-quality sections of its own
**[measured]**. Every other tier inherits engine values, which on this engine
version run from several hundred megabytes to a gigabyte, with the
video-memory clamp disabled at the top **[measured]**.
**[derived]** Two consequences, and the second is the one that matters:
1. The tier with the smallest declared budget is the only tier the project
actually configured. The rest are engine defaults that nobody chose.
2. Because a device profile applies at a higher priority than scalability, the
mid tier's pool **cannot be changed by the in-game texture setting**, while
on every other tier the same setting works. One control, opposite behaviour,
no explanation anywhere in the UI.
That asymmetry is the reason ST-01 leads the failure modes. It is not a mistake
in either file; it is a mistake that only exists between them.
---
## 2. Priority, in one paragraph you can act on
Device profiles apply variables whose names carry the scalability prefix at
**scalability** priority, and every other variable at **device-profile**
priority — which outranks everything the settings system does **[measured, from
engine source]**.
**[derived]** So the same file produces two completely different mutability
outcomes depending on a naming convention:
- a prefixed quality bucket set in a profile is a **default** the player can
override;
- an unprefixed variable set in a profile is a **lock**.
Nothing in the ini syntax distinguishes them. The audited project uses both
forms, mostly correctly and once consequentially (§1).
**The practical rule:** you cannot determine effective configuration by reading
files. Dump the variables with their source on the target device. That command is
the only authoritative answer, and it takes ten seconds.
---
## 3. Automatic detection promotes on the wrong axis
Promotion thresholds are expressed against a GPU performance index, for every
quality group, with **no memory term anywhere** **[measured]**. The texture group
reaches its top level at a low index value, and that top level is the one where
the engine disables the video-memory clamp on the pool **[measured]**.
**[derived]** A fast chip with modest memory therefore lands in the bucket that
grants the largest pool and removes the guard against it. The two decisions were
made in different files by different reasoning, and each is defensible alone.
The project's own comment on the thresholds is honest about their intent — tuning
so a specific generation of hardware lands in a specific mix **[measured]** — and
that intent is about throughput, which is exactly the axis that misses this.
Recipe: ST-02.
---
## 4. Dead configuration, and how much of it there is
Four independent instances, all silent, all reviewed at some point:
| Finding **[measured]** | What it means |
|---|---|
| A top-tier device profile section defined in full, absent from the profile registry and from the engine's base profiles | Every value in it is unreachable |
| Comment banners grouping devices under tier labels that contradict the base profile named two lines below | The documentation and the behaviour disagree; several devices sit under the wrong banner |
| A user-facing profile variant list read in three places and set in no configuration file | The profile override never applies; the console preset UI never appears |
| Optional mip levels configured in every mobile texture group, with chunk acquisition disabled | A high-resolution optional tier that cannot be delivered |
**[derived]** The common structure is worth naming, because it generalises far
beyond streaming: **configuration that names a mechanism the project does not
have.** It reads as a decision, survives review indefinitely, and produces
nothing. It is the configuration-file form of the stub described in
`ue-reference-project-adoption`.
Recipes: ST-05, ST-06, ST-07, ST-08.
---
## 5. Two arithmetic defects in the clamp layer
**A comparison between a percentage and a level.** A frame-rate compatibility
check obtains a resolution-quality limit — a percentage defaulting to one hundred
— and compares it against an overall quality level in the range zero to three
**[measured]**. The comparison is always satisfied, so the constraint never
binds.
**[derived]** What makes this findable rather than invisible is that the sibling
function two hundred lines away uses the correct accessor for the same purpose
**[measured]**. One of the two is wrong, and the codebase contains its own
counterexample.
**A remap with no guard on its denominator.** A normalisation between two
resolution ranges divides by the difference between a maximum and a minimum, with
no check that they differ, and the degenerate case is reachable from device
profile data **[measured]**.
Recipes: ST-09, ST-10. Both are three-line fixes and both would be caught by one
unit test each — which is the argument for testing clamps at their range
boundaries rather than at their typical values.
---
## 6. What the project got right
Worth stating, because the list above is long and the configuration is not bad:
1. **Cook-time budget levers are used deliberately.** Mobile texture groups clamp
the maximum size sixteen-fold on a side, animation key stripping is enabled,
and unused detail-mode components and emitters are pruned at cook
**[measured]**. These are budget-A decisions, correctly separated from
runtime budgets.
2. **Foliage density was moved between scalability groups deliberately**, with the
old group's keys removed and a different curve applied in the new one
**[measured]**. That is a real understanding of how the groups compose.
3. **Per-device resolution overrides on specific hardware** rather than a blanket
platform value **[measured]**.
4. **Dynamic resolution configured for one mobile platform** with an explicit
comment stating the target frame rate and output resolution **[measured]** —
the kind of comment that makes a number reviewable.
5. **A rich set of runtime diagnostics** already wired: the profile selection
logs its inputs and its chosen result, frame pacing logs its target, quality
clamping logs both the before and after values **[measured]**. Someone
arriving on a device has the answers available.
**[derived]** Point 5 deserves emphasis. Most of the findings in this file are
detectable in ten seconds on a device by reading log lines the project already
prints. The failure is not instrumentation; it is that nobody read the output.
---
## 7. What to copy, and what to check first
Copy: the four-budget separation as a documentation convention; cook-time levers
used per platform; the diagnostic logging around profile selection and clamping;
per-device overrides for outlier hardware.
Check first, in this order, on your own project:
1. **Dump variables with their source** on each target. Everything else is
inference. (ST-01)
2. **Diff declared profiles against defined sections.** One command. (ST-05)
3. **Separate reads from writes** for every data-driven selection list. (ST-07)
4. **Unit-test every clamp** at both ends of its range. (ST-09, ST-10)
5. **Check both pool values** — texture and mesh — on every platform. (ST-03)
**[derived]** Steps 1 and 2 take minutes and would have found the two largest
findings in this file. That ratio is the argument for doing configuration audits
at all.
---
## Provenance
Measured against Epic's Lyra Starter Game on Unreal Engine 5.6, read as project
configuration and source, cross-referenced against the engine's own scalability
and device-profile configuration and streaming source in the same installation.
Source addresses and engine paths stay in the research archive that produced this
skill; each `ST-` identifier resolves back to the audited location there.
## Evidence boundary
**Nothing here was profiled.** No device was measured, no memory figure is an
observation, and every quantity is a declared budget or a configured threshold.
Engine values describe one engine version and will drift. The recipes exist
precisely because these numbers must be re-derived on your project and your
hardware before they mean anything.