# EXP-002 — WordPress Abilities

## Objectif

Observer l’Abilities API réellement chargée par WordPress 7.0.4 : registre, catégories, métadonnées, provenance, exposition REST et contrôles de permission, sans créer ni exécuter d’Ability.

## Hypothèse

L’API PHP et le registre sont présents ; les métadonnées et les sources locales permettent de distinguer les capacités Core des capacités du plugin AI, tandis que REST peut révéler le namespace sans nécessairement révéler les listes.

## Environnement

`https://lab.quantumdev.fr` ; racine `/home/vawa9743/lab.quantumdev.fr` ; WordPress 7.0.4 ; PHP 8.4.24 ; WP-CLI 2.12.0 ; MariaDB 11.4.12 ; SSH fonctionnel.

## Préconditions

EXP-001 validé et laissé intact. Aucun identifiant, cookie, Application Password, clé API ou secret utilisé. Aucun utilisateur courant modifié.

## Documentation officielle utilisée

Référence officielle fournie pour l’expérience : Abilities API WordPress (disponible depuis 6.9), `WP_Abilities_Registry`, registre séparé des catégories, fonctions `wp_get_abilities()`, `wp_get_ability()`, `wp_get_ability_categories()`, namespace REST `wp-abilities/v1`, `meta.show_in_rest`, annotations `readonly`, `destructive` et `idempotent`.

## Manipulations

Lecture via `wp eval` des classes, fonctions, catégories, Abilities et métadonnées ; lecture ciblée des sources Core et du plugin `ai` pour les callbacks et origines ; trois GET anonymes des routes demandées ; GET de l’index REST ; recherche des modules JavaScript Core. Aucune Ability n’a été exécutée.

## Commandes

Collecteur reproductible : [collect-exp-002.sh](../../lab/scripts/collect-exp-002.sh). Les preuves de commandes et de réponses sont archivées dans `lab/output/EXP-002/`.

## Résultat attendu

Confirmer ou infirmer la présence de l’API, inventorier les objets effectivement enregistrés, distinguer découverte REST et accès aux données, et documenter les permissions sans contournement.

## Résultat observé

Les classes `WP_Ability`, `WP_Abilities_Registry`, `WP_Ability_Category` et les quatre fonctions demandées sont présentes. Le registre contient 8 Abilities et 4 catégories. Le namespace REST est visible anonymement ; les collections d’Abilities et de catégories nécessitent une authentification et renvoient HTTP 401 en anonyme.

## Abilities enregistrées

8 objets : `core/get-site-info`, `core/get-user-info`, `core/get-environment-info`, `core/read-settings`, `core/read-users`, `core/read-content`, `ai/get-post-details`, `ai/get-post-terms`.

6 déclarent `readonly=true` ; 2 (`ai/get-post-details`, `ai/get-post-terms`) ont `readonly`, `destructive` et `idempotent` à `null` dans leurs métadonnées. 0 déclare `destructive=true`. 6 déclarent `show_in_rest=true`.

## Catégories

4 catégories : `site`, `user`, `ai-experiments`, `content`. Les métadonnées publiques retournées par l’API catégorie sont vides (`meta=[]`) pour les quatre.

## Exposition REST

Le namespace `wp-abilities/v1` apparaît dans l’index REST. La route `/wp-abilities/v1/` répond HTTP 200 anonymement et expose la structure des routes. Les routes `/abilities` et `/categories` répondent HTTP 401 `rest_forbidden`. L’inventaire détaillé `show_in_rest` est dans [rest-exposure.txt](../../lab/output/EXP-002/rest-exposure.txt).

## Accès anonyme

Un visiteur anonyme peut découvrir l’existence du namespace, ses routes, méthodes et paramètres via la racine du namespace. Il ne peut pas obtenir les listes d’Abilities ou de catégories avec les GET testés. Aucune authentification n’a été contournée.

## Permissions

Les huit objets ont un callback de permission identifiable dans les enregistrements ou sources consultés. Le Core utilise `manage_options` pour les informations site/environnement et `is_user_logged_in()` pour l’information utilisateur. Le plugin `ai` utilise notamment `manage_options`, `is_user_logged_in()`, `list_users`, `edit_user`, `edit_post` et des contrôles dépendant du contenu/statut. Détail et références : [permissions.txt](../../lab/output/EXP-002/permissions.txt).

## Client-side Abilities

PRESENT, partiellement démontré au niveau des artefacts compilés : `wp-includes/js/dist/script-modules/abilities/` et `core-abilities/` contiennent les modules Core correspondants. Les métadonnées de package npm séparées ne sont pas établies.

## Logs / preuves

- [api-presence.txt](../../lab/output/EXP-002/api-presence.txt)
- [categories.json](../../lab/output/EXP-002/categories.json)
- [abilities.json](../../lab/output/EXP-002/abilities.json)
- [origins.txt](../../lab/output/EXP-002/origins.txt)
- [rest-anonymous.txt](../../lab/output/EXP-002/rest-anonymous.txt)
- [rest-discovery.txt](../../lab/output/EXP-002/rest-discovery.txt)
- [rest-exposure.txt](../../lab/output/EXP-002/rest-exposure.txt)
- [permissions.txt](../../lab/output/EXP-002/permissions.txt)
- [client-side.txt](../../lab/output/EXP-002/client-side.txt)
- [execution.txt](../../lab/output/EXP-002/execution.txt)

## Écart attendu / observé

La découverte du namespace est publique alors que les collections sont protégées par 401, ce qui confirme que visibilité REST et autorisation d’accès sont distinctes. Deux Abilities AI n’annoncent pas les annotations readonly/destructive/idempotent ; elles n’ont donc pas été exécutées.

## Risques

Les opérations sont read-only. Les réponses REST sont un état instantané et peuvent changer avec les plugins ou la configuration. Les schémas d’output ont été lus, mais aucune donnée d’exécution n’a été demandée.

## Rollback

Aucun rollback WordPress nécessaire : aucune écriture WordPress, DB, configuration ou fichier applicatif n’a été effectuée. Les seules écritures sont le collecteur et les preuves dans le lab.

## Conclusion

EXP-002 démontre la présence de l’Abilities API et son registre actif. L’installation expose 8 Abilities issues du Core et du plugin `ai`, mais l’accès anonyme aux inventaires REST est refusé. La sécurité d’exécution repose sur des callbacks de permission identifiables ; aucune Ability n’a été exécutée par prudence.

## Niveau de confiance

fort

## Production

acceptable sous conditions

## Matière éditoriale

### Fait

Le namespace Abilities est publiquement découvrable, mais ses collections sont protégées par HTTP 401.

### Surprise

Trois Abilities portent un nom `core/` tout en étant enregistrées ou remplacées par le plugin `ai` local ; le préfixe du nom ne suffit donc pas à prouver la provenance.

### Décision QuantumDev

Ne créer ni Ability personnalisée ni accès REST public avant une expérience dédiée sur les permissions et les effets.

### Chiffre

8 Abilities, 4 catégories, 6 `show_in_rest=true`, 0 `destructive=true` déclaré.

### Capture exploitable

GET `/wp-abilities/v1/` : 200 avec les routes ; GET `/abilities` et `/categories` : 401 `rest_forbidden`.

### Angle LinkedIn

« Une API peut révéler sa surface sans révéler ses données : mesurer séparément découverte, exposition et permission. »

### Niveau de preuve

démontré
