Repository: Qiskit/qiskit (python)

Issue:
`BlueprintCircuit` subclasses rebuild out-of-order after `_append`
### Environment

- **Qiskit Terra version**: 0.25.3
- **Python version**: 3.10
- **Operating system**: macOS


### What is happening?

Subclasses of `BlueprintCircuit` do not behave correctly when the inner-loop `_append` method is used; the circuit is not rebuilt prior to accepting the append.

### How can we reproduce the issue?

```python
from qiskit.circuit.library import RealAmplitudes, XGate
from qiskit.circuit import CircuitInstruction, ClassicalRegister

qc = RealAmplitudes(num_qubits=2, reps=2)
qc.add_register(ClassicalRegister(2, "meas"))
qc._append(CircuitInstruction(XGate(), (qc.qubits[0],), ()))
qc.draw()
```
gives
```
        ┌───┐┌────────────────────────────────────────────────┐
   q_0: ┤ X ├┤0                                               ├
        └───┘│  RealAmplitudes(θ[0],θ[1],θ[2],θ[3],θ[4],θ[5]) │
   q_1: ─────┤1                                               ├
             └────────────────────────────────────────────────┘
meas: 2/═══════════════════════════════════════════════════════
```

whereas using `QuantumCircuit.append` gives the expected:
```python
from qiskit.circuit.library import RealAmplitudes, XGate
from qiskit.circuit import CircuitInstruction, ClassicalRegister

qc = RealAmplitudes(num_qubits=2, reps=2)
qc.add_register(ClassicalRegister(2, "meas"))
qc.append(XGate(), [qc.qubits[0]])
qc.draw()
```
```
        ┌────────────────────────────────────────────────┐┌───┐
   q_0: ┤0                                               ├┤ X ├
        │  RealAmplitudes(θ[0],θ[1],θ[2],θ[3],θ[4],θ[5]) │└───┘
   q_1: ┤1                                               ├─────
        └────────────────────────────────────────────────┘
meas: 2/═══════════════════════════════════════════════════════
```

### What should happen?

Inner `_append` should handle enforcing the build, not `append`.

### Any suggestions?

_No response_

Pull request:
Fix build ordering of `BlueprintCircuit._append`
### Summary

`QuantumCircuit._append` is the actual append primitive and is allowed in inner-loop appends (and for `QuantumCircuit` to assume that it's callable from other methods), so it's important that the "ensure built" check happens there, not in `append`.

<!--
⚠️ If you do not respect this template, your pull request will be closed.
⚠️ Your pull request title should be short detailed and understandable for all.
⚠️ Also, please add a release note file using reno if the change needs to be
  documented in the release notes.
⚠️ If your pull request fixes an open issue, please link to the issue.

- [ ] I have added the tests to cover my changes.
- [ ] I have updated the documentation accordingly.
- [ ] I have read the CONTRIBUTING document.
-->


### Details and comments

Fix #11180.


Patch:
diff --git a/qiskit/circuit/library/blueprintcircuit.py b/qiskit/circuit/library/blueprintcircuit.py
index 415ae8ecd..082249e54 100644
--- a/qiskit/circuit/library/blueprintcircuit.py
+++ b/qiskit/circuit/library/blueprintcircuit.py
@@ -119,10 +119,10 @@ class BlueprintCircuit(QuantumCircuit, ABC):
             self._build()
         return super().qasm(formatted, filename, encoding)
 
-    def append(self, instruction, qargs=None, cargs=None):
+    def _append(self, instruction, _qargs=None, _cargs=None):
         if not self._is_built:
             self._build()
-        return super().append(instruction, qargs, cargs)
+        return super()._append(instruction, _qargs, _cargs)
 
     def compose(self, other, qubits=None, clbits=None, front=False, inplace=False, wrap=False):
         if not self._is_built:
diff --git a/qiskit/transpiler/passmanager.py b/qiskit/transpiler/passmanager.py
index 6ee5d702d..c9c67be05 100644
--- a/qiskit/transpiler/passmanager.py
+++ b/qiskit/transpiler/passmanager.py
@@ -65,7 +65,7 @@ class PassManager(BasePassManager):
         input_program: QuantumCircuit,
         **kwargs,
     ) -> DAGCircuit:
-        return circuit_to_dag(input_program, copy_operations=False)
+        return circuit_to_dag(input_program, copy_operations=True)
 
     def _passmanager_backend(
         self,
@@ -73,7 +73,7 @@ class PassManager(BasePassManager):
         in_program: QuantumCircuit,
         **kwargs,
     ) -> QuantumCircuit:
-        out_program = dag_to_circuit(passmanager_ir)
+        out_program = dag_to_circuit(passmanager_ir, copy_operations=False)
 
         out_name = kwargs.get("output_name", None)
         if out_name is not None:
diff --git a/releasenotes/notes/fix-blueprint-circuit-_append-b4d6c9c41db860f5.yaml b/releasenotes/notes/fix-blueprint-circuit-_append-b4d6c9c41db860f5.yaml
new file mode 100644
index 000000000..0596bc50d
--- /dev/null
+++ b/releasenotes/notes/fix-blueprint-circuit-_append-b4d6c9c41db860f5.yaml
@@ -0,0 +1,6 @@
+---
+fixes:
+  - |
+    :class:`.BlueprintCircuit` subclasses will now behave correctly when the semi-public method
+    :meth:`.QuantumCircuit._append` is used with the blueprint in an unbuilt state, *i.e.* the
+    circuit will be built before attempting the append.


Test patch:
diff --git a/test/python/circuit/library/test_blueprintcircuit.py b/test/python/circuit/library/test_blueprintcircuit.py
index 974e4c1ea..0ccd5c40e 100644
--- a/test/python/circuit/library/test_blueprintcircuit.py
+++ b/test/python/circuit/library/test_blueprintcircuit.py
@@ -16,8 +16,15 @@ import unittest
 from ddt import ddt, data
 
 from qiskit.test.base import QiskitTestCase
-from qiskit.circuit import QuantumRegister, Parameter, QuantumCircuit, Gate, Instruction
-from qiskit.circuit.library import BlueprintCircuit
+from qiskit.circuit import (
+    QuantumRegister,
+    Parameter,
+    QuantumCircuit,
+    Gate,
+    Instruction,
+    CircuitInstruction,
+)
+from qiskit.circuit.library import BlueprintCircuit, XGate
 
 
 class MockBlueprint(BlueprintCircuit):
@@ -139,6 +146,34 @@ class TestBlueprintCircuit(QiskitTestCase):
             gate = circuit.to_instruction()
             self.assertIsInstance(gate, Instruction)
 
+    def test_build_before_appends(self):
+        """Test that both forms of direct append (public and semi-public) function correctly."""
+
+        class DummyBlueprint(BlueprintCircuit):
+            """Dummy circuit."""
+
+            def _check_configuration(self, raise_on_failure=True):
+                return True
+
+            def _build(self):
+                super()._build()
+                self.z(0)
+
+        expected = QuantumCircuit(2)
+        expected.z(0)
+        expected.x(0)
+
+        qr = QuantumRegister(2, "q")
+        mock = DummyBlueprint()
+        mock.add_register(qr)
+        mock.append(XGate(), [qr[0]], [])
+        self.assertEqual(expected, mock)
+
+        mock = DummyBlueprint()
+        mock.add_register(qr)
+        mock._append(CircuitInstruction(XGate(), (qr[0],), ()))
+        self.assertEqual(expected, mock)
+
 
 if __name__ == "__main__":
     unittest.main()