Files
MagentaDolphin ecd87ac96d 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>
2026-09-05 23:48:55 +07:00

9.5 KiB

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.