our API surface is diffed against the client's 19,572 globals

- `--surface` re-runs the comparison against the captured in-world global table on demand, and `--surface-dump` writes our raw side for any tool to join — a one-shot measurement stops drifting
- CreateFrame with an unresolvable template raises exactly as the client does, instead of handing back a bare frame; `inherits=` is one name, matched case-insensitively
- CreateFontString and CreateTexture honour their third argument — 49 corpus call sites were passing an inherit into the void
- the addon-message inbound byte map is corrected (a test had agreed with the wrong constants), and the group-loot roll template publishes under the reference's own name

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Sam
2026-08-14 19:08:30 +07:00
co-authored by Claude Fable 5
parent a6aecb98df
commit d7f4c59fa8
19 changed files with 795 additions and 121 deletions
+9 -2
View File
@@ -209,9 +209,16 @@ pub fn apply_template(lua: &mlua::Lua, wrapper: &Table, kind: &str, template: &s
{
let model = loader.model();
let templates = model.framexml_templates.borrow();
for name in template.split(',').map(str::trim).filter(|s| !s.is_empty()) {
// One name, verbatim, folded — the same law `framexml::expand` resolves under, kept in
// step so this diagnostic cannot disagree with the resolution it describes.
for name in [template].into_iter().filter(|s| !s.is_empty()) {
// A name that is missing entirely is `expand`'s warning to give, just below.
let Some(el) = templates.get(name) else {
let Some(el) = templates.get(name).or_else(|| {
templates
.iter()
.find(|(k, _)| k.eq_ignore_ascii_case(name))
.map(|(_, v)| v)
}) else {
continue;
};
any_resolved = true;
+5 -3
View File
@@ -270,16 +270,18 @@ impl Loader<'_> {
let model = self.model();
let fonts = model.framexml_fonts.borrow();
let templates = model.framexml_templates.borrow();
for entry in inherits.split(',').map(str::trim) {
// One name, not a comma list — 1.12's lookup has no splitter, and supporting one is a
// superset of it. Folded on the probe, like the resolution itself.
for entry in [inherits] {
let mut name = entry.to_string();
for _ in 0..MAX_HOPS {
if fonts.contains_key(&name) {
if fonts.contains_key(&name) || fonts.keys().any(|k| k.eq_ignore_ascii_case(&name))
{
return Some(name);
}
let Some(next) = templates
.get(&name)
.and_then(|t| t.attr("inherits"))
.and_then(|i| i.split(',').map(str::trim).next())
.map(str::to_string)
else {
break;