Verified against origin/development with git show.
Summary
MetadataService::extractUuid() (lib/Service/MetadataService.php:564) probes:
if (is_object($dashboard) === true && method_exists($dashboard, 'getUuid') === true) {
$dashboard is launchpad's own OCA\Launchpad\Db\Dashboard, which extends OCP\AppFramework\Db\Entity and declares getUuid() as an @method docblock (lib/Db/Dashboard.php:30). Nextcloud's Entity serves it through __call(), so method_exists() is false and the method returns null.
Its caller filterDashboards() then continues every dashboard and returns [].
Measured
Live, against the server's own lib/public/AppFramework/Db/Entity.php:
| subject |
method_exists |
is_callable |
an Entity subclass's docblock-only accessor |
false |
true |
| a genuinely concrete method — control |
true |
true |
🔴 Entity::getId |
false |
true |
Consequence: latent, not live
filterDashboards() has zero callers anywhere in launchpad — no PHP, JS, Vue or test reference. So nothing is broken for users today.
Filing it anyway because it is a loaded gun: the first caller wired to it gets a total metadata-filter blackout, and the failure is silent — an empty list is indistinguishable from "nothing matched". Wiring it up would look like the new caller's bug.
Why this one matters beyond launchpad
This is the fleet's clearest proof that the pattern is not an OpenRegister problem. It is a Nextcloud Entity problem, and it bites an app against its own entity.
launchpad has 21 entity files declaring @method accessors. Any method_exists() probe against any of them is false.
Related in this repo:
lib/Service/DashboardVersionService.php:764 — method_exists($entity, $setter) with a variable name, which a literal-name grep cannot see.
lib/Service/DashboardVersionService.php:560 — probes getContentBackend, a method I could not find defined anywhere in the fleet. Possibly a phantom; worth confirming against whatever supplies that object.
Fix notes
is_callable() is not a membership test on a __call class — measured, it is true for any name, and the call then raises BadFunctionCallException. Swapping the probe yields an always-true guard, so make the call exception-safe in the same edit.
For an entity you own, property_exists($entity, 'uuid') is the better probe: it is a genuine membership test. openregister's MultiTenancyTrait uses exactly that, twice, for this reason.
Do not fall back to getId() — it is magic too.
Fleet context and the full 18-repo table: fleet-board/findings/method-exists-sweep.md.
Verified against
origin/developmentwithgit show.Summary
MetadataService::extractUuid()(lib/Service/MetadataService.php:564) probes:$dashboardis launchpad's ownOCA\Launchpad\Db\Dashboard, which extendsOCP\AppFramework\Db\Entityand declaresgetUuid()as an@methoddocblock (lib/Db/Dashboard.php:30). Nextcloud'sEntityserves it through__call(), somethod_exists()is false and the method returnsnull.Its caller
filterDashboards()thencontinues every dashboard and returns[].Measured
Live, against the server's own
lib/public/AppFramework/Db/Entity.php:method_existsis_callableEntitysubclass's docblock-only accessorEntity::getIdConsequence: latent, not live
filterDashboards()has zero callers anywhere in launchpad — no PHP, JS, Vue or test reference. So nothing is broken for users today.Filing it anyway because it is a loaded gun: the first caller wired to it gets a total metadata-filter blackout, and the failure is silent — an empty list is indistinguishable from "nothing matched". Wiring it up would look like the new caller's bug.
Why this one matters beyond launchpad
This is the fleet's clearest proof that the pattern is not an OpenRegister problem. It is a Nextcloud
Entityproblem, and it bites an app against its own entity.launchpad has 21 entity files declaring
@methodaccessors. Anymethod_exists()probe against any of them is false.Related in this repo:
lib/Service/DashboardVersionService.php:764—method_exists($entity, $setter)with a variable name, which a literal-name grep cannot see.lib/Service/DashboardVersionService.php:560— probesgetContentBackend, a method I could not find defined anywhere in the fleet. Possibly a phantom; worth confirming against whatever supplies that object.Fix notes
is_callable()is not a membership test on a__callclass — measured, it is true for any name, and the call then raisesBadFunctionCallException. Swapping the probe yields an always-true guard, so make the call exception-safe in the same edit.For an entity you own,
property_exists($entity, 'uuid')is the better probe: it is a genuine membership test. openregister'sMultiTenancyTraituses exactly that, twice, for this reason.Do not fall back to
getId()— it is magic too.Fleet context and the full 18-repo table:
fleet-board/findings/method-exists-sweep.md.