﻿id	summary	reporter	owner	description	type	status	priority	milestone	component	version	severity	resolution	keywords	cc	focuses
65248	Abilities API: add `wp_ability_invoked` action for pipeline-entry observers	gziolo	gziolo	"The execution lifecycle filters proposed in #64989 give the Abilities API four seams: `wp_pre_execute_ability`, `wp_before_execute_ability`, `wp_after_execute_ability`, and `wp_execute_ability_result`. `wp_before_execute_ability` fires after input normalization, validation, and the permission check — its contract is ""execution is imminent."" That contract is correct: rate-limiter, cached-response, and dry-run observers all rely on it not firing for calls that exit early.

That leaves a gap for audit and snapshot observers, which need the opposite signal: ""the pipeline received this invocation, regardless of outcome."" They want a hook that fires for every call — approval-pending, rate-limited, cached, dry-run, and normal — so the audit row exists no matter how the call exits, and fires before normalization so the input is captured raw.

== Proposal ==

Add a `wp_ability_invoked` action at the top of `WP_Ability::execute()`, before `wp_pre_execute_ability` runs:

{{{
#!php
do_action( 'wp_ability_invoked', $this->name, $input, $this );
}}}

The argument shape mirrors `wp_before_execute_ability` so observers can attach the same callback signature to both hooks. The past-tense verb communicates ""entered the pipeline"" without implying the call will execute.

== Lifecycle position ==

{{{
execute( $input ) {
    do_action( 'wp_ability_invoked', ... );      // new — every call, raw input
    apply_filters( 'wp_pre_execute_ability', ... ); // existing — short-circuit seam
    // normalize_input → validate_input → check_permissions
    do_action( 'wp_before_execute_ability', ... ); // existing — execution imminent
    // execute_callback
    do_action( 'wp_after_execute_ability', ... );
    return apply_filters( 'wp_execute_ability_result', ... );
}
}}}

== Motivation ==

Surfaced in [https://github.com/WordPress/ai/discussions/477#discussioncomment-16900589 WordPress/ai#477]. The AbilityGuard plugin currently writes its audit row inline inside its `wp_pre_execute_ability` handler because no earlier signal exists, which conflates ""build the approval envelope"" with ""record that an invocation happened."" Landing `wp_ability_invoked` lets that work move to a dedicated observer listener and keeps the pre-execute handler focused on its short-circuit responsibility.

The same signal benefits any observability layer that needs invocation entry counts independent of outcome (telemetry, rate-limit accounting that includes rejected calls, etc.)."	enhancement	closed	normal	7.1	Abilities API	6.9	normal	fixed	has-patch has-unit-tests needs-dev-note		
