Scope
An Android model name comes from one of two places. Built-in profiles ship with the SDK's cmdline-tools and are read with avdmanager list device. Custom profiles are read from Android Studio's devices.xml in the user's .android directory. A name in both resolves to the built-in one. Simlock never writes either.
The user docs say none of this. An operator cannot tell why a model exists on one machine and not on another, or how to add one. In a fleet, a custom profile exists only on the worker whose user made it.
After this task the user docs describe both sources, and the catalog marks which models are custom.
Technical spec
File references are to main at 4f84a6a. Find code by symbol name.
Modules touched
src/core/driver.ts: DriverCatalogEntry gains customModels?: readonly string[]. Each name is a value from the entry's models. It means "this model exists because of something on this machine, not because of the platform's tools". The core carries it and never reads it. A driver with no such models omits the field.
src/drivers/android/device-profile-source.ts: DeviceProfileCatalog gains customModels: the listed models whose winning profile is of kind properties. A name in both sources is listed once, resolves to the built-in profile, and is not custom. DeviceProfileRegistry.catalog() builds it from the same deduplicated list it builds models from, so the mark and the resolution cannot disagree.
src/drivers/android/index.ts: listCatalog passes customModels through, omitted when empty.
src/drivers/ios/index.ts: no change. It omits the field.
src/contract/schemas.ts: the platform catalog schema gains optional customModels: an array of strings, bounded by the same limit as the models it is a subset of, each string bounded like a model name. Add the limit to CATALOG_LIST_LIMITS.
src/gateway/aggregate.ts: in the fleet catalog a model is in customModels when at least one worker that lists it marks it custom. A name a worker marks custom but does not list in models is dropped. The per-worker catalog in the worker view carries that worker's own list unchanged.
src/cli/index.ts: formatCatalog marks each custom model with (custom) after its name. --json carries the field as is. The human view of worker list, where it prints a worker's models, uses the same mark.
src/core/fake-driver.ts, e2e/fake-driver/fake-driver.ts: scriptable customModels.
- Docs:
docs/CLI.md, a short section under catalog: Android models come from the SDK's built-in profiles and from Android Studio's custom profiles in devices.xml; the built-in one wins on a name clash; a newer built-in model needs newer cmdline-tools; a custom profile is made with Android Studio's device manager on that machine, and exists only there; in a fleet it is leasable only on the worker that has it. Simlock reads both and writes neither. Describe the (custom) mark and the customModels field.
docs/HTTP-API.md and docs/CLIENT.md: customModels on the catalog and on the worker view.
Contract and event changes
catalog.get, and the catalog inside the worker view, gain optional customModels per platform. Additive. It ships as part of protocol 9; no bump.
- No event change.
Rules in play
architecture.md rule 1 and 2 (the core and the gateway carry the list unread; only the Android driver knows what makes a model custom), rule 10 (one deduplicated list decides both which profile a name resolves to and whether it is custom).
safety.md rule 1 (both sources are read, never written) and rule 10 (a worker's customModels is a claim: the gateway bounds it and drops names the worker does not list).
- ADR 0008 (the catalog says what a worker can make).
documentation.md rule 2 and 3.
testing.md rules 1 to 4.
Tests
- A model that comes only from
devices.xml is listed in customModels.
- A built-in model is not in
customModels.
- A name in both sources is listed once and is not in
customModels.
- An unreadable
devices.xml yields the built-in models and no customModels.
- With no custom profile, the Android catalog entry has no
customModels field.
- The iOS catalog entry has no
customModels field.
- A model in
customModels resolves to a profile of kind properties.
- The fleet catalog marks a model custom when one worker marks it and another lists it as built-in.
- The gateway drops a custom name the worker does not list in
models.
- A worker's
customModels over the limit is refused by the schema.
- The worker view's catalog carries that worker's own
customModels.
simlock catalog prints (custom) after a custom model and not after a built-in one.
Done when
docs/CLI.md says where Android models come from, which source wins on a name clash, that a newer built-in model needs newer cmdline-tools, and that a custom profile is added with Android Studio's device manager on that machine.
simlock catalog --json marks each Android model that comes from devices.xml as custom. Built-in models and iOS models carry no mark.
- The human view of
simlock catalog shows the same mark.
- On a gateway, the worker list shows the mark per worker.
- An unreadable
devices.xml still yields the built-in models, as today.
pnpm check is green.
Out of scope
- A Simlock-owned profile file.
- Copying profiles between workers.
- Writing or editing
devices.xml.
- Routing on the mark. A gateway already sends a request only to a worker that lists the model.
Depends on
Approval
Written by an agent.
Scope
An Android model name comes from one of two places. Built-in profiles ship with the SDK's
cmdline-toolsand are read withavdmanager list device. Custom profiles are read from Android Studio'sdevices.xmlin the user's.androiddirectory. A name in both resolves to the built-in one. Simlock never writes either.The user docs say none of this. An operator cannot tell why a model exists on one machine and not on another, or how to add one. In a fleet, a custom profile exists only on the worker whose user made it.
After this task the user docs describe both sources, and the catalog marks which models are custom.
Technical spec
File references are to
mainat 4f84a6a. Find code by symbol name.Modules touched
src/core/driver.ts:DriverCatalogEntrygainscustomModels?: readonly string[]. Each name is a value from the entry'smodels. It means "this model exists because of something on this machine, not because of the platform's tools". The core carries it and never reads it. A driver with no such models omits the field.src/drivers/android/device-profile-source.ts:DeviceProfileCataloggainscustomModels: the listed models whose winning profile is of kindproperties. A name in both sources is listed once, resolves to the built-in profile, and is not custom.DeviceProfileRegistry.catalog()builds it from the same deduplicated list it buildsmodelsfrom, so the mark and the resolution cannot disagree.src/drivers/android/index.ts:listCatalogpassescustomModelsthrough, omitted when empty.src/drivers/ios/index.ts: no change. It omits the field.src/contract/schemas.ts: the platform catalog schema gains optionalcustomModels: an array of strings, bounded by the same limit as the models it is a subset of, each string bounded like a model name. Add the limit toCATALOG_LIST_LIMITS.src/gateway/aggregate.ts: in the fleet catalog a model is incustomModelswhen at least one worker that lists it marks it custom. A name a worker marks custom but does not list inmodelsis dropped. The per-worker catalog in the worker view carries that worker's own list unchanged.src/cli/index.ts:formatCatalogmarks each custom model with(custom)after its name.--jsoncarries the field as is. The human view ofworker list, where it prints a worker's models, uses the same mark.src/core/fake-driver.ts,e2e/fake-driver/fake-driver.ts: scriptablecustomModels.docs/CLI.md, a short section undercatalog: Android models come from the SDK's built-in profiles and from Android Studio's custom profiles indevices.xml; the built-in one wins on a name clash; a newer built-in model needs newercmdline-tools; a custom profile is made with Android Studio's device manager on that machine, and exists only there; in a fleet it is leasable only on the worker that has it. Simlock reads both and writes neither. Describe the(custom)mark and thecustomModelsfield.docs/HTTP-API.mdanddocs/CLIENT.md:customModelson the catalog and on the worker view.Contract and event changes
catalog.get, and the catalog inside the worker view, gain optionalcustomModelsper platform. Additive. It ships as part of protocol 9; no bump.Rules in play
architecture.mdrule 1 and 2 (the core and the gateway carry the list unread; only the Android driver knows what makes a model custom), rule 10 (one deduplicated list decides both which profile a name resolves to and whether it is custom).safety.mdrule 1 (both sources are read, never written) and rule 10 (a worker'scustomModelsis a claim: the gateway bounds it and drops names the worker does not list).documentation.mdrule 2 and 3.testing.mdrules 1 to 4.Tests
devices.xmlis listed incustomModels.customModels.customModels.devices.xmlyields the built-in models and nocustomModels.customModelsfield.customModelsfield.customModelsresolves to a profile of kindproperties.models.customModelsover the limit is refused by the schema.customModels.simlock catalogprints(custom)after a custom model and not after a built-in one.Done when
docs/CLI.mdsays where Android models come from, which source wins on a name clash, that a newer built-in model needs newercmdline-tools, and that a custom profile is added with Android Studio's device manager on that machine.simlock catalog --jsonmarks each Android model that comes fromdevices.xmlas custom. Built-in models and iOS models carry no mark.simlock catalogshows the same mark.devices.xmlstill yields the built-in models, as today.pnpm checkis green.Out of scope
devices.xml.Depends on
Approval
Written by an agent.