null, 'truncated' => false, 'original_bytes' => 0, ); } $bytes = strlen( $json ); if ( 0 === $limit || $bytes <= $limit ) { return array( 'json' => $json, 'truncated' => false, 'original_bytes' => $bytes, ); } $marker = array( self::MARKER_KEY => true, 'original_bytes' => $bytes, 'kind' => $kind, ); return array( 'json' => Json::canonical( $marker ), 'truncated' => true, 'original_bytes' => $bytes, ); } /** * Apply a byte cap per-surface to a surfaces map. * * A $limit of 0 means "no cap" for all surfaces. Each surface is evaluated * independently: surfaces within budget survive intact; over-budget surfaces * are replaced with a structured marker. * * Measurement is on `Json::canonical($surface_value)` - uncompressed. * * @param array $surfaces Map of surface-name => collected data. * @param int $limit Per-surface byte limit (0 = unlimited). * * @return array{ surfaces: array, truncated: array } */ public static function cap_surfaces( array $surfaces, int $limit ): array { if ( 0 === $limit ) { return array( 'surfaces' => $surfaces, 'truncated' => array(), ); } $result = array(); $truncated = array(); foreach ( $surfaces as $surface => $data ) { $json = Json::canonical( $data ); $bytes = strlen( $json ); if ( $bytes <= $limit ) { $result[ $surface ] = $data; } else { $truncated[ $surface ] = $bytes; $result[ $surface ] = array( self::MARKER_KEY => true, 'original_bytes' => $bytes, 'surface' => $surface, ); } } return array( 'surfaces' => $result, 'truncated' => $truncated, ); } }