) and the audit-log ability column value. * * @return string */ abstract public function slug(); /** * Static metadata describing the operation for agents and wrappers. * * Contract (keys consumed downstream in M4): * slug string same as slug() * risk string 'none' | 'low' | 'medium' | 'high' * summary string agent-facing description (when to call, what changes) * annotations array truthful MCP annotations, e.g. * { destructive: bool, idempotent: bool, readonly: bool } * input_schema array JSON schema for the ability input * * @return array */ abstract public function describe(); /** * Preview the operation without mutating anything. Returns the common * output shape with dry_run = true. * * @param array $input * @return array */ abstract public function dry_run( $input ); /** * Execute the operation. Returns the common output shape with * dry_run = false. * * @param array $input * @return array */ abstract public function run( $input ); /** * True when this operation is high-risk (dry-run defaults to true and a * confirm token is required to execute). Derived from describe()['risk']. * * @return bool */ public function is_high_risk() { $atb_meta = $this->describe(); return isset( $atb_meta['risk'] ) && 'high' === $atb_meta['risk']; } /** * Builds the common mutating-output shape (spec §2.1). * * @param bool $performed Whether a mutation actually happened. * @param bool $dry_run Whether this was a dry run. * @param array $details Operation-specific details. * @param array $warnings Non-fatal warnings (list of strings). * @return array */ protected function output( $performed, $dry_run, $details = array(), $warnings = array() ) { return array( 'performed' => (bool) $performed, 'dry_run' => (bool) $dry_run, 'details' => is_array( $details ) ? $details : array(), 'warnings' => array_values( array_map( 'strval', (array) $warnings ) ), ); } /** * Validates that an array conforms to the common output shape. Used by * unit tests and defensively by wrappers. * * @param mixed $atb_output * @return bool */ public static function is_valid_output( $atb_output ) { if ( ! is_array( $atb_output ) ) { return false; } foreach ( array( 'performed', 'dry_run', 'details', 'warnings' ) as $atb_key ) { if ( ! array_key_exists( $atb_key, $atb_output ) ) { return false; } } if ( ! is_bool( $atb_output['performed'] ) || ! is_bool( $atb_output['dry_run'] ) ) { return false; } if ( ! is_array( $atb_output['details'] ) || ! is_array( $atb_output['warnings'] ) ) { return false; } foreach ( $atb_output['warnings'] as $atb_warning ) { if ( ! is_string( $atb_warning ) ) { return false; } } return true; } } }