Spaces:
Sleeping
Sleeping
| defined( 'ABSPATH' ) || exit; | |
| /** | |
| * Demand Registration Hook. | |
| * | |
| * A surface object (ticket, task, subscriber) is NOT automatically a | |
| * Demand. It exists operationally on its surface (Fluent Support, Fluent | |
| * Boards, FluentCRM) but is invisible to Asterion's trace/audit/closure | |
| * logic until explicitly registered. | |
| * | |
| * This class provides that registration. It writes an arbitration row | |
| * (the canonical first entry of a Demand lifecycle) through the surface | |
| * adapter — never via direct $wpdb access to surface tables. | |
| * | |
| * v1 surface: a single static method, callable from PHP. Future: | |
| * an admin UI button or REST endpoint can wrap this. | |
| * | |
| * Demand Registration Boundary (per doctrine): | |
| * - Unregistered surface objects remain operational but do NOT | |
| * participate in trace, audit, or closure logic. | |
| * - They are referred to as "untracked demand candidates" until | |
| * registered. | |
| */ | |
| class SA_Orch_Demand_Registry { | |
| /** | |
| * Register a surface object as an Asterion Demand. | |
| * | |
| * @param string $surface Surface id (must have a registered adapter). | |
| * @param string $ref Surface-specific ref (must validate via adapter). | |
| * @param string $rationale Human-readable rationale for arbitration. | |
| * @param string $projection_type Default 'scope-direct-no-plan'; see SA_Orch_Arbitration::write. | |
| * @param string $truth_class Default 'canonical'. | |
| * | |
| * @return array|WP_Error Arbitration row data on success; WP_Error on failure. | |
| */ | |
| public static function register( | |
| string $surface, | |
| string $ref, | |
| string $rationale, | |
| string $projection_type = 'scope-direct-no-plan', | |
| string $truth_class = 'canonical' | |
| ) { | |
| $adapter = SA_Orch_Bridge_Fluent::adapter_for( $surface ); | |
| if ( ! $adapter ) { | |
| return new WP_Error( | |
| 'no_adapter', | |
| "No surface adapter registered for '{$surface}'." | |
| ); | |
| } | |
| if ( ! $adapter->validate( $ref ) ) { | |
| return new WP_Error( | |
| 'invalid_ref', | |
| "Ref '{$ref}' does not resolve under the '{$surface}' adapter." | |
| ); | |
| } | |
| return SA_Orch_Arbitration::write( [ | |
| 'demand_surface' => $surface, | |
| 'demand_ref' => $ref, | |
| 'rationale' => $rationale, | |
| 'projection_type' => $projection_type, | |
| 'truth_class' => $truth_class, | |
| ] ); | |
| } | |
| /** | |
| * Convenience: is this surface object already registered as a Demand? | |
| * Returns true if at least one arbitration exists for the (surface, ref) pair. | |
| */ | |
| public static function is_registered( string $surface, string $ref ): bool { | |
| global $wpdb; | |
| $arb_table = $wpdb->prefix . SA_ORCH_DB_PREFIX . 'arbitration'; | |
| $count = (int) $wpdb->get_var( $wpdb->prepare( | |
| "SELECT COUNT(*) FROM {$arb_table} WHERE demand_surface = %s AND demand_ref = %s", | |
| $surface, $ref | |
| ) ); | |
| return $count > 0; | |
| } | |
| } | |