You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
An Android model's class comes from the listed profile, not the one its name resolves to #341
On Android, a model's class in the catalog comes from the profile it was listed from (src/drivers/android/device-profile-source.ts:122). customModels (:116) and leasing use the profile the name resolves to. If a devices.xml profile has the same name as an SDK profile id, such as tv_1080p or wearos_large_round, the catalog lists it as phone. But leasing it creates the SDK TV or Wear OS profile.
Why it matters
Today nothing picks a device by class, so nothing breaks yet. Once a class request picks a model (#334), such a name could be picked for phone and come up as a TV or a watch.
Expected
A model's class is the class of the profile a lease of that name creates.
Update: leasing by class has shipped (#343, #357), so a model listed under the wrong class can now be granted to a class request. The note that nothing picks by class yet no longer holds. The code is unchanged: src/drivers/android/device-profile-source.ts:119-122 takes the class from the listed profile, while customModels (:113-118) uses the profile the name resolves to.
Confirmed on current main (the 2026-10-09 note holds: the code is unchanged, and class matching now consumes modelClasses in leasing — classCandidates/modelClass at src/leasing/lease-acquisition-coordinator.ts:477-500 — and in gateway routing — src/gateway/routing/request-match.ts:57,83).
Test: src/drivers/android/device-profile-source.test.ts — "classes a listed model by the profile its name resolves to, not the one it was listed from" (branch bug/341-repro, commit 2617fb61)
Command: pnpm exec vitest run --project unit src/drivers/android/device-profile-source.test.ts
Failing assertion (expect(catalog.modelClasses).toEqual(expected), expected built from registry.resolve per model):
The fixture is a devices.xml with three profiles named after SDK profile ids — two the library also ships, one (tv_720p) the SDK only — proving both the library-shipped and the SDK-only collision shapes. The test also asserts resolve on each name really returns the SDK/library TV or Wear OS profile. Read-only check of a real SDK (avdmanager list device, cmdline-tools latest): id: 58 or "tv_1080p" Tag android-tv, id: 61 or "wearos_large_round" Tag android-wear, so the collision is realistic; nothing in parseDevicesXml validates names against profile ids.
Root cause
Defect.src/drivers/android/device-profile-source.ts:135-138 builds modelClasses by iterating listed.values() — the profile each name was listed from — while customModels (:130-133) and modelProfiles/modelRuntimes (:140-144) project every name through matchProfile, and resolve — what provisioning creates — resolves the same way. A name that a library or SDK profile also answers to is therefore classified from the wrong profile, and every class-based reader of the catalog (leasing's classCandidates, the gateway's class filter, MCP/CLI) sees, e.g., a TV-listed tv_1080p as phone.
Simplest fix
Class by the resolved profile, like the other catalog fields: iterate models, take matchProfile(profiles, model), keep the existing classification expression (properties → classOfTag(imageKind), else deviceClass). With exactly that change the new test passes and all 13 unit files of src/drivers/android (617 tests) stay green.
Alternatives rejected
Enrich the listed profile's class from the resolving profile's details — fixes only the devices.xml shape, not the library/SDK collisions, and re-implements matchProfile.
Refuse to list a model whose name is another profile's alias — contradicts the listing rule pinned by "does not list another name that an earlier profile answers to", which keeps such models listed on purpose.
Re-resolve the class through the driver at lease/route time — routing sees only the catalog record; this pushes driver knowledge into leasing and the gateway.
Risk
The change alters modelClasses only where listed profile ≠ resolved profile; confirm the leasing/gateway/core preference-list and classDefaults tests stay green (the drivers' own suite does).
A host with such a colliding name on android.defaultModels.phone will stop granting it a phone-class lease and take the next candidate or UnknownModelError — that is the fix working.
Reviews: round 1 (spec/code/claims) — 1 blocking claims finding on the triage test's comment, verified and fixed as text; fix check on the post-review commits: clean. Manual updated within its line budget; docs/CLI.md states the classing rule.
Activity
V3RON commentedon Oct 9, 2026
Update: leasing by class has shipped (#343, #357), so a model listed under the wrong class can now be granted to a class request. The note that nothing picks by class yet no longer holds. The code is unchanged:
src/drivers/android/device-profile-source.ts:119-122takes the class from the listed profile, whilecustomModels(:113-118) uses the profile the name resolves to.Written by an agent.
test: reproduce #341 — a listed model's class comes from the listed p…
V3RON commentedon Oct 16, 2026
Reproduction
Confirmed on current main (the 2026-10-09 note holds: the code is unchanged, and class matching now consumes
modelClassesin leasing —classCandidates/modelClassatsrc/leasing/lease-acquisition-coordinator.ts:477-500— and in gateway routing —src/gateway/routing/request-match.ts:57,83).src/drivers/android/device-profile-source.test.ts— "classes a listed model by the profile its name resolves to, not the one it was listed from" (branchbug/341-repro, commit2617fb61)pnpm exec vitest run --project unit src/drivers/android/device-profile-source.test.tsexpect(catalog.modelClasses).toEqual(expected), expected built fromregistry.resolveper model):The fixture is a
devices.xmlwith three profiles named after SDK profile ids — two the library also ships, one (tv_720p) the SDK only — proving both the library-shipped and the SDK-only collision shapes. The test also assertsresolveon each name really returns the SDK/library TV or Wear OS profile. Read-only check of a real SDK (avdmanager list device, cmdline-tools latest):id: 58 or "tv_1080p"Tagandroid-tv,id: 61 or "wearos_large_round"Tagandroid-wear, so the collision is realistic; nothing inparseDevicesXmlvalidates names against profile ids.Root cause
Defect.
src/drivers/android/device-profile-source.ts:135-138buildsmodelClassesby iteratinglisted.values()— the profile each name was listed from — whilecustomModels(:130-133) andmodelProfiles/modelRuntimes(:140-144) project every name throughmatchProfile, andresolve— what provisioning creates — resolves the same way. A name that a library or SDK profile also answers to is therefore classified from the wrong profile, and every class-based reader of the catalog (leasing'sclassCandidates, the gateway's class filter, MCP/CLI) sees, e.g., a TV-listedtv_1080pasphone.Simplest fix
Class by the resolved profile, like the other catalog fields: iterate
models, takematchProfile(profiles, model), keep the existing classification expression (properties→classOfTag(imageKind), elsedeviceClass). With exactly that change the new test passes and all 13 unit files ofsrc/drivers/android(617 tests) stay green.Alternatives rejected
matchProfile.Risk
modelClassesonly where listed profile ≠ resolved profile; confirm the leasing/gateway/core preference-list andclassDefaultstests stay green (the drivers' own suite does).android.defaultModels.phonewill stop granting it a phone-class lease and take the next candidate orUnknownModelError— that is the fix working.Written by an agent.
test: state the resolving profile per colliding name in the #341 test…
V3RON commentedon Oct 16, 2026
Delivery run
Merged: #646 (#341)
Parked: none
Waiting: none
Reviews: round 1 (spec/code/claims) — 1 blocking claims finding on the triage test's comment, verified and fixed as text; fix check on the post-review commits: clean. Manual updated within its line budget;
docs/CLI.mdstates the classing rule.Written by an agent.