Looking at some of the internals, it looks like return_value_policy::reference_internal is only "activated" when an instance is created newly registered:
https://github.com/pybind/pybind11/blob/48e1f9a/include/pybind11/cast.h#L552
However, py::keep_alive<N, P>() looks like it is always activated:
https://github.com/pybind/pybind11/blob/48e1f9a/include/pybind11/pybind11.h#L140
https://github.com/pybind/pybind11/blob/48e1f9a/include/pybind11/attr.h#L442
https://github.com/pybind/pybind11/blob/48e1f9a/include/pybind11/pybind11.h#L1470
https://github.com/pybind/pybind11/blob/48e1f9a/include/pybind11/detail/class.h#L289
A simple fix (for only pybind-registered objects) would be to add a simple check:
#include <algorithm>
...
auto& p = internals.patients[nurse];
if (std::find(p.begin(), p.end(), patient) != p.end()) ...
This would impact performance a little, but would prevent a packrat problem for long(er)-running Python programs.
Not sure about the non-pybind case in keep_alive_impl; however, it looks like this would just leak some reference counting, which may be less of an issue than an array growing.