why the processing is sometimes terminated , sometimes not
You can force the same behaviour accross errors with SET XACT_ABORT

SET XACT_ABORT ON;


From the documentation:


  Specifies whether SQL Server automatically rolls back the current
  transaction when a Transact-SQL statement raises a run-time error.


Source

By default XACT_ABORT = OFF this means that different errors create different outcomes.

To force the behaviour on error to be the same, add SET XACT_ABORT ON; at the beginning of your script.



Testing with your example

SET XACT_ABORT ON;

DECLARE @Error int;
INSERT INTO Person.BusinessEntityContact
 (BusinessEntityID
 ,PersonID
 ,ContactTypeID)
 VALUES
 (0,0,1);
SELECT @Error = @@ERROR;
PRINT 'The Value of @Error is ‘ + CONVERT(varchar, @Error)'


With the only error shown:


  Msg 547, Level 16, State 0, Line 17 The INSERT statement conflicted
  with the FOREIGN KEY constraint "FK_Person". The conflict occurred in
  database "my_test", table "Person.Person", column 'PersonID'.




Also note this important statement regarding error handling and SET XACT_ABORT


  The THROW statement honors SET XACT_ABORT. RAISERROR does not.
  New applications should use THROW instead of RAISERROR.


Source