)]}'
{"id":"couchbase-python-client~251939","triplet_id":"couchbase-python-client~master~Iff6addc219263e7020ec86a96b80509c4fe98e17","project":"couchbase-python-client","branch":"master","attention_set":{},"removed_from_attention_set":{"1004568":{"account":{"_account_id":1004568,"name":"Jared Casey","email":"jared.casey@couchbase.com","username":"thejcfactor","avatars":[{"url":"https://www.gravatar.com/avatar/20ac69da8a1fb4cc11bdd1c880389132.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d32","height":32},{"url":"https://www.gravatar.com/avatar/20ac69da8a1fb4cc11bdd1c880389132.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d56","height":56},{"url":"https://www.gravatar.com/avatar/20ac69da8a1fb4cc11bdd1c880389132.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d100","height":100},{"url":"https://www.gravatar.com/avatar/20ac69da8a1fb4cc11bdd1c880389132.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d120","height":120}]},"last_update":"2026-08-28 18:00:01.000000000","reason":"Change was submitted"}},"hashtags":[],"change_id":"Iff6addc219263e7020ec86a96b80509c4fe98e17","subject":"PYCBC-1923: Keep the built-in observability implementations working","status":"MERGED","created":"2026-08-27 22:51:15.000000000","updated":"2026-08-28 18:00:01.000000000","submitted":"2026-08-28 18:00:01.000000000","submitter":{"_account_id":1004568,"name":"Jared Casey","email":"jared.casey@couchbase.com","username":"thejcfactor","avatars":[{"url":"https://www.gravatar.com/avatar/20ac69da8a1fb4cc11bdd1c880389132.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d32","height":32},{"url":"https://www.gravatar.com/avatar/20ac69da8a1fb4cc11bdd1c880389132.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d56","height":56},{"url":"https://www.gravatar.com/avatar/20ac69da8a1fb4cc11bdd1c880389132.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d100","height":100},{"url":"https://www.gravatar.com/avatar/20ac69da8a1fb4cc11bdd1c880389132.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d120","height":120}]},"total_comment_count":0,"unresolved_comment_count":0,"has_review_started":true,"submission_id":"251939","meta_rev_id":"70ca37329b02a353a4346b7f7e8774c5a1cd780f","_number":251939,"virtual_id_number":251939,"owner":{"_account_id":1004568,"name":"Jared Casey","email":"jared.casey@couchbase.com","username":"thejcfactor","avatars":[{"url":"https://www.gravatar.com/avatar/20ac69da8a1fb4cc11bdd1c880389132.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d32","height":32},{"url":"https://www.gravatar.com/avatar/20ac69da8a1fb4cc11bdd1c880389132.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d56","height":56},{"url":"https://www.gravatar.com/avatar/20ac69da8a1fb4cc11bdd1c880389132.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d100","height":100},{"url":"https://www.gravatar.com/avatar/20ac69da8a1fb4cc11bdd1c880389132.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d120","height":120}]},"actions":{},"labels":{"Verified":{"approved":{"_account_id":1000011,"name":"Build Bot","email":"build@couchbase.com","username":"buildbot","avatars":[{"url":"https://www.gravatar.com/avatar/0ba35a43c05d6329d9b2136bab05a733.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d32","height":32},{"url":"https://www.gravatar.com/avatar/0ba35a43c05d6329d9b2136bab05a733.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d56","height":56},{"url":"https://www.gravatar.com/avatar/0ba35a43c05d6329d9b2136bab05a733.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d100","height":100},{"url":"https://www.gravatar.com/avatar/0ba35a43c05d6329d9b2136bab05a733.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d120","height":120}],"tags":["SERVICE_USER"]},"all":[{"value":0,"_account_id":1005035,"name":"Dimitris Christodoulou","email":"dimitris.christodoulou@couchbase.com","username":"DemetrisChr","avatars":[{"url":"https://www.gravatar.com/avatar/4291f7baa025a5558b77019a9c264ab2.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d32","height":32},{"url":"https://www.gravatar.com/avatar/4291f7baa025a5558b77019a9c264ab2.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d56","height":56},{"url":"https://www.gravatar.com/avatar/4291f7baa025a5558b77019a9c264ab2.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d100","height":100},{"url":"https://www.gravatar.com/avatar/4291f7baa025a5558b77019a9c264ab2.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d120","height":120}]},{"tag":"autogenerated:gerrit:merged","value":1,"date":"2026-08-28 18:00:01.000000000","permitted_voting_range":{"min":1,"max":1},"_account_id":1000011,"name":"Build Bot","email":"build@couchbase.com","username":"buildbot","avatars":[{"url":"https://www.gravatar.com/avatar/0ba35a43c05d6329d9b2136bab05a733.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d32","height":32},{"url":"https://www.gravatar.com/avatar/0ba35a43c05d6329d9b2136bab05a733.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d56","height":56},{"url":"https://www.gravatar.com/avatar/0ba35a43c05d6329d9b2136bab05a733.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d100","height":100},{"url":"https://www.gravatar.com/avatar/0ba35a43c05d6329d9b2136bab05a733.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d120","height":120}],"tags":["SERVICE_USER"]},{"value":0,"_account_id":1004568,"name":"Jared Casey","email":"jared.casey@couchbase.com","username":"thejcfactor","avatars":[{"url":"https://www.gravatar.com/avatar/20ac69da8a1fb4cc11bdd1c880389132.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d32","height":32},{"url":"https://www.gravatar.com/avatar/20ac69da8a1fb4cc11bdd1c880389132.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d56","height":56},{"url":"https://www.gravatar.com/avatar/20ac69da8a1fb4cc11bdd1c880389132.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d100","height":100},{"url":"https://www.gravatar.com/avatar/20ac69da8a1fb4cc11bdd1c880389132.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d120","height":120}]}],"values":{"-1":"Fails"," 0":"No score","+1":"Verified"},"description":"","default_value":0},"Code-Review":{"approved":{"_account_id":1005035,"name":"Dimitris Christodoulou","email":"dimitris.christodoulou@couchbase.com","username":"DemetrisChr","avatars":[{"url":"https://www.gravatar.com/avatar/4291f7baa025a5558b77019a9c264ab2.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d32","height":32},{"url":"https://www.gravatar.com/avatar/4291f7baa025a5558b77019a9c264ab2.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d56","height":56},{"url":"https://www.gravatar.com/avatar/4291f7baa025a5558b77019a9c264ab2.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d100","height":100},{"url":"https://www.gravatar.com/avatar/4291f7baa025a5558b77019a9c264ab2.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d120","height":120}]},"all":[{"tag":"autogenerated:gerrit:merged","value":2,"date":"2026-08-28 18:00:01.000000000","permitted_voting_range":{"min":2,"max":2},"_account_id":1005035,"name":"Dimitris Christodoulou","email":"dimitris.christodoulou@couchbase.com","username":"DemetrisChr","avatars":[{"url":"https://www.gravatar.com/avatar/4291f7baa025a5558b77019a9c264ab2.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d32","height":32},{"url":"https://www.gravatar.com/avatar/4291f7baa025a5558b77019a9c264ab2.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d56","height":56},{"url":"https://www.gravatar.com/avatar/4291f7baa025a5558b77019a9c264ab2.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d100","height":100},{"url":"https://www.gravatar.com/avatar/4291f7baa025a5558b77019a9c264ab2.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d120","height":120}]},{"value":0,"_account_id":1000011,"name":"Build Bot","email":"build@couchbase.com","username":"buildbot","avatars":[{"url":"https://www.gravatar.com/avatar/0ba35a43c05d6329d9b2136bab05a733.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d32","height":32},{"url":"https://www.gravatar.com/avatar/0ba35a43c05d6329d9b2136bab05a733.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d56","height":56},{"url":"https://www.gravatar.com/avatar/0ba35a43c05d6329d9b2136bab05a733.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d100","height":100},{"url":"https://www.gravatar.com/avatar/0ba35a43c05d6329d9b2136bab05a733.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d120","height":120}],"tags":["SERVICE_USER"]},{"value":0,"_account_id":1004568,"name":"Jared Casey","email":"jared.casey@couchbase.com","username":"thejcfactor","avatars":[{"url":"https://www.gravatar.com/avatar/20ac69da8a1fb4cc11bdd1c880389132.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d32","height":32},{"url":"https://www.gravatar.com/avatar/20ac69da8a1fb4cc11bdd1c880389132.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d56","height":56},{"url":"https://www.gravatar.com/avatar/20ac69da8a1fb4cc11bdd1c880389132.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d100","height":100},{"url":"https://www.gravatar.com/avatar/20ac69da8a1fb4cc11bdd1c880389132.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d120","height":120}]}],"values":{"-2":"Do not submit","-1":"I would prefer that you didn\u0027t submit this"," 0":"No score","+1":"Looks good to me, but someone else must approve","+2":"Looks good to me, approved"},"description":"","default_value":0},"Well-Formed":{"all":[{"value":0,"_account_id":1005035,"name":"Dimitris Christodoulou","email":"dimitris.christodoulou@couchbase.com","username":"DemetrisChr","avatars":[{"url":"https://www.gravatar.com/avatar/4291f7baa025a5558b77019a9c264ab2.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d32","height":32},{"url":"https://www.gravatar.com/avatar/4291f7baa025a5558b77019a9c264ab2.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d56","height":56},{"url":"https://www.gravatar.com/avatar/4291f7baa025a5558b77019a9c264ab2.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d100","height":100},{"url":"https://www.gravatar.com/avatar/4291f7baa025a5558b77019a9c264ab2.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d120","height":120}]},{"value":0,"_account_id":1000011,"name":"Build Bot","email":"build@couchbase.com","username":"buildbot","avatars":[{"url":"https://www.gravatar.com/avatar/0ba35a43c05d6329d9b2136bab05a733.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d32","height":32},{"url":"https://www.gravatar.com/avatar/0ba35a43c05d6329d9b2136bab05a733.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d56","height":56},{"url":"https://www.gravatar.com/avatar/0ba35a43c05d6329d9b2136bab05a733.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d100","height":100},{"url":"https://www.gravatar.com/avatar/0ba35a43c05d6329d9b2136bab05a733.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d120","height":120}],"tags":["SERVICE_USER"]},{"value":0,"_account_id":1004568,"name":"Jared Casey","email":"jared.casey@couchbase.com","username":"thejcfactor","avatars":[{"url":"https://www.gravatar.com/avatar/20ac69da8a1fb4cc11bdd1c880389132.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d32","height":32},{"url":"https://www.gravatar.com/avatar/20ac69da8a1fb4cc11bdd1c880389132.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d56","height":56},{"url":"https://www.gravatar.com/avatar/20ac69da8a1fb4cc11bdd1c880389132.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d100","height":100},{"url":"https://www.gravatar.com/avatar/20ac69da8a1fb4cc11bdd1c880389132.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d120","height":120}]}],"values":{"-1":"Commit is not well-formed"," 0":"Well-formedness not checked","+1":"Commit is well-formed"},"description":"","default_value":0,"optional":true}},"removable_reviewers":[],"reviewers":{"REVIEWER":[{"_account_id":1000011,"name":"Build Bot","email":"build@couchbase.com","username":"buildbot","avatars":[{"url":"https://www.gravatar.com/avatar/0ba35a43c05d6329d9b2136bab05a733.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d32","height":32},{"url":"https://www.gravatar.com/avatar/0ba35a43c05d6329d9b2136bab05a733.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d56","height":56},{"url":"https://www.gravatar.com/avatar/0ba35a43c05d6329d9b2136bab05a733.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d100","height":100},{"url":"https://www.gravatar.com/avatar/0ba35a43c05d6329d9b2136bab05a733.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d120","height":120}],"tags":["SERVICE_USER"]},{"_account_id":1004568,"name":"Jared Casey","email":"jared.casey@couchbase.com","username":"thejcfactor","avatars":[{"url":"https://www.gravatar.com/avatar/20ac69da8a1fb4cc11bdd1c880389132.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d32","height":32},{"url":"https://www.gravatar.com/avatar/20ac69da8a1fb4cc11bdd1c880389132.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d56","height":56},{"url":"https://www.gravatar.com/avatar/20ac69da8a1fb4cc11bdd1c880389132.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d100","height":100},{"url":"https://www.gravatar.com/avatar/20ac69da8a1fb4cc11bdd1c880389132.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d120","height":120}]},{"_account_id":1005035,"name":"Dimitris Christodoulou","email":"dimitris.christodoulou@couchbase.com","username":"DemetrisChr","avatars":[{"url":"https://www.gravatar.com/avatar/4291f7baa025a5558b77019a9c264ab2.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d32","height":32},{"url":"https://www.gravatar.com/avatar/4291f7baa025a5558b77019a9c264ab2.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d56","height":56},{"url":"https://www.gravatar.com/avatar/4291f7baa025a5558b77019a9c264ab2.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d100","height":100},{"url":"https://www.gravatar.com/avatar/4291f7baa025a5558b77019a9c264ab2.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d120","height":120}]}]},"pending_reviewers":{},"reviewer_updates":[{"updated":"2026-08-27 22:51:24.000000000","updated_by":{"_account_id":1000011,"name":"Build Bot","email":"build@couchbase.com","username":"buildbot","avatars":[{"url":"https://www.gravatar.com/avatar/0ba35a43c05d6329d9b2136bab05a733.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d32","height":32},{"url":"https://www.gravatar.com/avatar/0ba35a43c05d6329d9b2136bab05a733.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d56","height":56},{"url":"https://www.gravatar.com/avatar/0ba35a43c05d6329d9b2136bab05a733.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d100","height":100},{"url":"https://www.gravatar.com/avatar/0ba35a43c05d6329d9b2136bab05a733.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d120","height":120}],"tags":["SERVICE_USER"]},"reviewer":{"_account_id":1000011,"name":"Build Bot","email":"build@couchbase.com","username":"buildbot","avatars":[{"url":"https://www.gravatar.com/avatar/0ba35a43c05d6329d9b2136bab05a733.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d32","height":32},{"url":"https://www.gravatar.com/avatar/0ba35a43c05d6329d9b2136bab05a733.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d56","height":56},{"url":"https://www.gravatar.com/avatar/0ba35a43c05d6329d9b2136bab05a733.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d100","height":100},{"url":"https://www.gravatar.com/avatar/0ba35a43c05d6329d9b2136bab05a733.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d120","height":120}],"tags":["SERVICE_USER"]},"state":"CC"},{"updated":"2026-08-27 23:54:45.000000000","updated_by":{"_account_id":1000011,"name":"Build Bot","email":"build@couchbase.com","username":"buildbot","avatars":[{"url":"https://www.gravatar.com/avatar/0ba35a43c05d6329d9b2136bab05a733.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d32","height":32},{"url":"https://www.gravatar.com/avatar/0ba35a43c05d6329d9b2136bab05a733.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d56","height":56},{"url":"https://www.gravatar.com/avatar/0ba35a43c05d6329d9b2136bab05a733.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d100","height":100},{"url":"https://www.gravatar.com/avatar/0ba35a43c05d6329d9b2136bab05a733.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d120","height":120}],"tags":["SERVICE_USER"]},"reviewer":{"_account_id":1000011,"name":"Build Bot","email":"build@couchbase.com","username":"buildbot","avatars":[{"url":"https://www.gravatar.com/avatar/0ba35a43c05d6329d9b2136bab05a733.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d32","height":32},{"url":"https://www.gravatar.com/avatar/0ba35a43c05d6329d9b2136bab05a733.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d56","height":56},{"url":"https://www.gravatar.com/avatar/0ba35a43c05d6329d9b2136bab05a733.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d100","height":100},{"url":"https://www.gravatar.com/avatar/0ba35a43c05d6329d9b2136bab05a733.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d120","height":120}],"tags":["SERVICE_USER"]},"state":"REVIEWER"},{"updated":"2026-08-28 16:59:28.000000000","updated_by":{"_account_id":1005035,"name":"Dimitris Christodoulou","email":"dimitris.christodoulou@couchbase.com","username":"DemetrisChr","avatars":[{"url":"https://www.gravatar.com/avatar/4291f7baa025a5558b77019a9c264ab2.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d32","height":32},{"url":"https://www.gravatar.com/avatar/4291f7baa025a5558b77019a9c264ab2.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d56","height":56},{"url":"https://www.gravatar.com/avatar/4291f7baa025a5558b77019a9c264ab2.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d100","height":100},{"url":"https://www.gravatar.com/avatar/4291f7baa025a5558b77019a9c264ab2.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d120","height":120}]},"reviewer":{"_account_id":1005035,"name":"Dimitris Christodoulou","email":"dimitris.christodoulou@couchbase.com","username":"DemetrisChr","avatars":[{"url":"https://www.gravatar.com/avatar/4291f7baa025a5558b77019a9c264ab2.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d32","height":32},{"url":"https://www.gravatar.com/avatar/4291f7baa025a5558b77019a9c264ab2.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d56","height":56},{"url":"https://www.gravatar.com/avatar/4291f7baa025a5558b77019a9c264ab2.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d100","height":100},{"url":"https://www.gravatar.com/avatar/4291f7baa025a5558b77019a9c264ab2.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d120","height":120}]},"state":"REVIEWER"}],"messages":[{"id":"40f99fa1da1cfe7738eb1552a4261bbae09aa5bf","tag":"autogenerated:gerrit:newPatchSet","author":{"_account_id":1004568,"name":"Jared Casey","email":"jared.casey@couchbase.com","username":"thejcfactor","avatars":[{"url":"https://www.gravatar.com/avatar/20ac69da8a1fb4cc11bdd1c880389132.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d32","height":32},{"url":"https://www.gravatar.com/avatar/20ac69da8a1fb4cc11bdd1c880389132.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d56","height":56},{"url":"https://www.gravatar.com/avatar/20ac69da8a1fb4cc11bdd1c880389132.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d100","height":100},{"url":"https://www.gravatar.com/avatar/20ac69da8a1fb4cc11bdd1c880389132.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d120","height":120}]},"date":"2026-08-27 22:51:15.000000000","message":"Uploaded patch set 1.","accounts_in_message":[],"_revision_number":1},{"id":"b25d0f8773162b27170df2bb5034ae21eba6bbf3","author":{"_account_id":1000011,"name":"Build Bot","email":"build@couchbase.com","username":"buildbot","avatars":[{"url":"https://www.gravatar.com/avatar/0ba35a43c05d6329d9b2136bab05a733.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d32","height":32},{"url":"https://www.gravatar.com/avatar/0ba35a43c05d6329d9b2136bab05a733.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d56","height":56},{"url":"https://www.gravatar.com/avatar/0ba35a43c05d6329d9b2136bab05a733.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d100","height":100},{"url":"https://www.gravatar.com/avatar/0ba35a43c05d6329d9b2136bab05a733.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d120","height":120}],"tags":["SERVICE_USER"]},"date":"2026-08-27 22:51:24.000000000","message":"Patch Set 1:\n\nBuild Started https://sdk.jenkins.couchbase.com/job/python/job/sdk/job/python-gerrit-trigger/7693/","accounts_in_message":[],"_revision_number":1},{"id":"6d976a30a73be7a1c2dc5b5031b9103a1b772e62","author":{"_account_id":1000011,"name":"Build Bot","email":"build@couchbase.com","username":"buildbot","avatars":[{"url":"https://www.gravatar.com/avatar/0ba35a43c05d6329d9b2136bab05a733.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d32","height":32},{"url":"https://www.gravatar.com/avatar/0ba35a43c05d6329d9b2136bab05a733.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d56","height":56},{"url":"https://www.gravatar.com/avatar/0ba35a43c05d6329d9b2136bab05a733.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d100","height":100},{"url":"https://www.gravatar.com/avatar/0ba35a43c05d6329d9b2136bab05a733.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d120","height":120}],"tags":["SERVICE_USER"]},"date":"2026-08-27 23:54:45.000000000","message":"Patch Set 1: Verified+1\n\nBuild Successful \n\nhttps://sdk.jenkins.couchbase.com/job/python/job/sdk/job/python-gerrit-trigger/7693/ : SUCCESS","accounts_in_message":[],"_revision_number":1},{"id":"168eb6f90d42e6157f765cdaafa517636bc6bbe3","tag":"autogenerated:gerrit:newPatchSet","author":{"_account_id":1004568,"name":"Jared Casey","email":"jared.casey@couchbase.com","username":"thejcfactor","avatars":[{"url":"https://www.gravatar.com/avatar/20ac69da8a1fb4cc11bdd1c880389132.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d32","height":32},{"url":"https://www.gravatar.com/avatar/20ac69da8a1fb4cc11bdd1c880389132.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d56","height":56},{"url":"https://www.gravatar.com/avatar/20ac69da8a1fb4cc11bdd1c880389132.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d100","height":100},{"url":"https://www.gravatar.com/avatar/20ac69da8a1fb4cc11bdd1c880389132.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d120","height":120}]},"date":"2026-08-28 16:48:33.000000000","message":"Patch Set 2: Patch Set 1 was rebased\n\nOutdated Votes:\n* Verified+1 (copy condition: \"changekind:NO_CHANGE OR changekind:NO_CODE_CHANGE\")\n","accounts_in_message":[],"_revision_number":2},{"id":"92dea65d509cc711c9992fcdc8b0012a6594c355","author":{"_account_id":1000011,"name":"Build Bot","email":"build@couchbase.com","username":"buildbot","avatars":[{"url":"https://www.gravatar.com/avatar/0ba35a43c05d6329d9b2136bab05a733.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d32","height":32},{"url":"https://www.gravatar.com/avatar/0ba35a43c05d6329d9b2136bab05a733.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d56","height":56},{"url":"https://www.gravatar.com/avatar/0ba35a43c05d6329d9b2136bab05a733.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d100","height":100},{"url":"https://www.gravatar.com/avatar/0ba35a43c05d6329d9b2136bab05a733.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d120","height":120}],"tags":["SERVICE_USER"]},"date":"2026-08-28 16:48:41.000000000","message":"Patch Set 2:\n\nBuild Started https://sdk.jenkins.couchbase.com/job/python/job/sdk/job/python-gerrit-trigger/7700/","accounts_in_message":[],"_revision_number":2},{"id":"00a2426c3c0ce981a57fd43a302852ac44cb3523","author":{"_account_id":1005035,"name":"Dimitris Christodoulou","email":"dimitris.christodoulou@couchbase.com","username":"DemetrisChr","avatars":[{"url":"https://www.gravatar.com/avatar/4291f7baa025a5558b77019a9c264ab2.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d32","height":32},{"url":"https://www.gravatar.com/avatar/4291f7baa025a5558b77019a9c264ab2.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d56","height":56},{"url":"https://www.gravatar.com/avatar/4291f7baa025a5558b77019a9c264ab2.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d100","height":100},{"url":"https://www.gravatar.com/avatar/4291f7baa025a5558b77019a9c264ab2.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d120","height":120}]},"date":"2026-08-28 16:59:28.000000000","message":"Patch Set 2: Code-Review+2","accounts_in_message":[],"_revision_number":2},{"id":"2ad576d2d5a503b711eb9fdb7f3b965933280ff9","author":{"_account_id":1000011,"name":"Build Bot","email":"build@couchbase.com","username":"buildbot","avatars":[{"url":"https://www.gravatar.com/avatar/0ba35a43c05d6329d9b2136bab05a733.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d32","height":32},{"url":"https://www.gravatar.com/avatar/0ba35a43c05d6329d9b2136bab05a733.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d56","height":56},{"url":"https://www.gravatar.com/avatar/0ba35a43c05d6329d9b2136bab05a733.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d100","height":100},{"url":"https://www.gravatar.com/avatar/0ba35a43c05d6329d9b2136bab05a733.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d120","height":120}],"tags":["SERVICE_USER"]},"date":"2026-08-28 17:58:26.000000000","message":"Patch Set 2: Verified+1\n\nBuild Successful \n\nhttps://sdk.jenkins.couchbase.com/job/python/job/sdk/job/python-gerrit-trigger/7700/ : SUCCESS","accounts_in_message":[],"_revision_number":2},{"id":"70ca37329b02a353a4346b7f7e8774c5a1cd780f","tag":"autogenerated:gerrit:merged","author":{"_account_id":1004568,"name":"Jared Casey","email":"jared.casey@couchbase.com","username":"thejcfactor","avatars":[{"url":"https://www.gravatar.com/avatar/20ac69da8a1fb4cc11bdd1c880389132.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d32","height":32},{"url":"https://www.gravatar.com/avatar/20ac69da8a1fb4cc11bdd1c880389132.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d56","height":56},{"url":"https://www.gravatar.com/avatar/20ac69da8a1fb4cc11bdd1c880389132.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d100","height":100},{"url":"https://www.gravatar.com/avatar/20ac69da8a1fb4cc11bdd1c880389132.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d120","height":120}]},"date":"2026-08-28 18:00:01.000000000","message":"Change has been successfully cherry-picked as d196673e41082aafb28cd28765d7af581090c017","accounts_in_message":[],"_revision_number":3}],"current_revision_number":3,"current_revision":"d196673e41082aafb28cd28765d7af581090c017","revisions":{"eaf41c5cfd44a178891649e5486c4f26fd840251":{"kind":"REWORK","_number":1,"created":"2026-08-27 22:51:15.000000000","uploader":{"_account_id":1004568,"name":"Jared Casey","email":"jared.casey@couchbase.com","username":"thejcfactor","avatars":[{"url":"https://www.gravatar.com/avatar/20ac69da8a1fb4cc11bdd1c880389132.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d32","height":32},{"url":"https://www.gravatar.com/avatar/20ac69da8a1fb4cc11bdd1c880389132.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d56","height":56},{"url":"https://www.gravatar.com/avatar/20ac69da8a1fb4cc11bdd1c880389132.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d100","height":100},{"url":"https://www.gravatar.com/avatar/20ac69da8a1fb4cc11bdd1c880389132.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d120","height":120}]},"ref":"refs/changes/39/251939/1","fetch":{"anonymous http":{"url":"https://review.couchbase.org/couchbase-python-client","ref":"refs/changes/39/251939/1","commands":{"Branch":"git fetch https://review.couchbase.org/couchbase-python-client refs/changes/39/251939/1 \u0026\u0026 git checkout -b change-251939 FETCH_HEAD","Checkout":"git fetch https://review.couchbase.org/couchbase-python-client refs/changes/39/251939/1 \u0026\u0026 git checkout FETCH_HEAD","Cherry Pick":"git fetch https://review.couchbase.org/couchbase-python-client refs/changes/39/251939/1 \u0026\u0026 git cherry-pick FETCH_HEAD","Format Patch":"git fetch https://review.couchbase.org/couchbase-python-client refs/changes/39/251939/1 \u0026\u0026 git format-patch -1 --stdout FETCH_HEAD","Pull":"git pull https://review.couchbase.org/couchbase-python-client refs/changes/39/251939/1","Reset To":"git fetch https://review.couchbase.org/couchbase-python-client refs/changes/39/251939/1 \u0026\u0026 git reset --hard FETCH_HEAD"}}},"commit":{"parents":[{"commit":"3eef2f75aa4734924d4e9685cd97497f75de123a","subject":"PYCBC-1885: Stop asserting a nonzero vbucket id in the token verifiers"}],"author":{"name":"Jared Casey","email":"jared.casey@couchbase.com","date":"2026-08-27 22:27:12.000000000","tz":-360},"committer":{"name":"Jared Casey","email":"jared.casey@couchbase.com","date":"2026-08-27 22:49:40.000000000","tz":-360},"subject":"PYCBC-1923: Keep the built-in observability implementations working","message":"PYCBC-1923: Keep the built-in observability implementations working\n\nChanges\n--------\n* LoggingMeter.create_report read each service\u0027s recorders with\n  ConcurrentMap.flush(), which does not copy, it detaches: it swaps in a\n  fresh dict and returns the old one.  On its own that would only lose\n  the registration, because value_recorder calls get_or_create.  It does\n  not, because _recorder_cache keys recorders by (service, operation)\n  and short circuits ahead of get_or_create.  So every operation after\n  the first report recorded into a LoggingValueRecorder no longer\n  reachable from self._recorders, and create_report never visited it\n  again.  A process configured with LoggingMeter logged exactly one\n  report and then went silent for its lifetime.  Iterate with items()\n  instead, which leaves the recorders registered\n* flush() was correct when value_recorder went through the map on\n  every call: detaching it meant the next call rebuilt the recorder in\n  the fresh map.  _recorder_cache holds the recorder directly, so the\n  write path stopped consulting the map and the detach no longer\n  rebuilds anything.  The contract broke, not the method\n* Keeping flush() would have meant invalidating _recorder_cache in the\n  same step, and that cache is deliberately lock-free.  Its own comment\n  reasons that two threads racing the slow path write the same value,\n  which holds only because entries are never removed.  Add removal and\n  a reader can take an entry pointing at a recorder that has just been\n  detached; the value it records is then lost rather than deferred,\n  because nothing reports that recorder again.  Closing the window\n  needs a lock on the per-operation path, which is what the cache\n  exists to avoid.  Iterating has no such window: a late write lands\n  in a registered recorder and is counted next interval\n* Iterating makes the recorders permanent, which is the cost of this\n  approach and is bounded by the enums.  Eight services and 146\n  operations is 1168 recorders, measured at 1.2 MiB for the full set,\n  and any real workload touches a small fraction of it\n* The flush was not needed for interval accounting either:\n  LoggingValueRecorder.get_percentiles_and_reset already resets the\n  underlying histogram, so each report still covers only its own\n  interval.  Measured across three consecutive reports.  flush() was\n  doing two jobs and only the unregistering one was unique to it,\n  which is the job that was wrong\n* Guard the per-operation entry on total_count rather than on the\n  report\u0027s truthiness.  get_percentiles_and_reset returns a two-key\n  dict whatever it finds, so `if percentile_report:` was always true and\n  did not do what it reads as.  That did not matter while flush()\n  removed idle recorders from the map; with items() it does, and without\n  this an idle interval would report a zero-valued entry for every\n  operation the process has ever performed\n* NoOpTracer.request_span returned NoOpSpan(), but NoOpSpan.__init__\n  takes name as a required positional parameter, so the call raised\n  TypeError: __init__() missing 1 required positional argument: \u0027name\u0027.\n  NoOpTracer is how tracing is turned off, so tracing could not be\n  disabled on any path that creates a span.  Forward what the caller\n  passed instead, including the parent_span and start_time that were\n  being dropped\n* Widen NoOpSpan.__init__\u0027s parent_span to Optional[RequestSpan] to\n  match what request_span accepts.  Forwarding an Optional[RequestSpan]\n  into a parameter declared Optional[NoOpSpan] is the one type error the\n  fix would otherwise introduce, and NoOpSpan discards the argument\n* ClusterImpl.close_connection stopped the tracer\u0027s reporter and never\n  the meter\u0027s.  LoggingMeter.close() exists and stops its reporter, and\n  nothing outside the tests called it, so a closed cluster kept a\n  LoggingMeterReporter alive and emitting.  Add the meter branch beside\n  the tracer branch\n* AsyncClusterImpl.close_connection had the same gap and one more: it\n  read self._cluster_settings.tracer.tracer where the synchronous path\n  reads .observability_instruments.tracer.tracer.  ClusterSettings is a\n  dataclass with an observability_instruments field and no tracer field,\n  so the read raised AttributeError inside a try whose except Exception\n  swallowed it, and the asynchronous path stopped neither reporter.\n  txcouchbase inherits this through close_connection_deferred\n* Both instruments are installed by default, so neither leak needed a\n  configured cluster to reproduce.  Both reporter threads set daemon,\n  so the process still exits; the cost is a reporter per cluster that\n  keeps running and emitting after close, accumulating across open and\n  close cycles.  Measured against 7.6.10 with default ClusterOptions:\n  one leaked thread per cycle synchronously and two asynchronously,\n  zero either way with this applied\n* Add test_reports_every_interval to the LoggingMeter suite and a\n  no-op tracer suite in couchbase/tests/no_op_observability_t.py.  All\n  three fail against the unfixed tree and need no cluster.  The existing\n  test_reset_after_report already pins the idle-interval behavior and\n  still passes, which is what the total_count guard preserves\n* Remove ConcurrentMap.flush().  Nothing calls it once create_report\n  iterates, and the class is private to this module: it is neither\n  exported nor named anywhere else in couchbase, acouchbase or\n  txcouchbase, tests included.  Leaving it would leave the trap that\n  caused this defect sitting beside the code that fell into it\n* Record at _recorder_cache why self._recorders may not be replaced.\n  The cache is what pins the recorders, so the constraint belongs with\n  the thing that imposes it rather than with the loop that has to\n  respect it\n* The bare except Exception in the shutdown path is what hid the\n  asynchronous defect from every test.  Narrowing it would change\n  behavior on unrelated shutdown errors, so it is left alone here\n\nChange-Id: Iff6addc219263e7020ec86a96b80509c4fe98e17\n"},"parents_data":[{"branch_name":"refs/heads/master","commit_id":"3eef2f75aa4734924d4e9685cd97497f75de123a","is_merged_in_target_branch":true,"change_id":"I24fdf14cac31482b574faca1e853fc116a8cef8f","change_number":251886,"patch_set_number":2,"change_status":"MERGED"}],"branch":"refs/heads/master"},"47cf711946a0cd93be09b9c747c0036f3ebf172a":{"kind":"TRIVIAL_REBASE","_number":2,"created":"2026-08-28 16:48:33.000000000","uploader":{"_account_id":1004568,"name":"Jared Casey","email":"jared.casey@couchbase.com","username":"thejcfactor","avatars":[{"url":"https://www.gravatar.com/avatar/20ac69da8a1fb4cc11bdd1c880389132.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d32","height":32},{"url":"https://www.gravatar.com/avatar/20ac69da8a1fb4cc11bdd1c880389132.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d56","height":56},{"url":"https://www.gravatar.com/avatar/20ac69da8a1fb4cc11bdd1c880389132.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d100","height":100},{"url":"https://www.gravatar.com/avatar/20ac69da8a1fb4cc11bdd1c880389132.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d120","height":120}]},"ref":"refs/changes/39/251939/2","fetch":{"anonymous http":{"url":"https://review.couchbase.org/couchbase-python-client","ref":"refs/changes/39/251939/2","commands":{"Branch":"git fetch https://review.couchbase.org/couchbase-python-client refs/changes/39/251939/2 \u0026\u0026 git checkout -b change-251939 FETCH_HEAD","Checkout":"git fetch https://review.couchbase.org/couchbase-python-client refs/changes/39/251939/2 \u0026\u0026 git checkout FETCH_HEAD","Cherry Pick":"git fetch https://review.couchbase.org/couchbase-python-client refs/changes/39/251939/2 \u0026\u0026 git cherry-pick FETCH_HEAD","Format Patch":"git fetch https://review.couchbase.org/couchbase-python-client refs/changes/39/251939/2 \u0026\u0026 git format-patch -1 --stdout FETCH_HEAD","Pull":"git pull https://review.couchbase.org/couchbase-python-client refs/changes/39/251939/2","Reset To":"git fetch https://review.couchbase.org/couchbase-python-client refs/changes/39/251939/2 \u0026\u0026 git reset --hard FETCH_HEAD"}}},"commit":{"parents":[{"commit":"9e7ee02fc137011195ddf2c3c4b0b46b1eaa77cb","subject":"PYCBC-1895: Correct the variadic options annotations on query methods"}],"author":{"name":"Jared Casey","email":"jared.casey@couchbase.com","date":"2026-08-27 22:27:12.000000000","tz":-360},"committer":{"name":"Jared Casey","email":"jared.casey@couchbase.com","date":"2026-08-28 16:48:33.000000000","tz":0},"subject":"PYCBC-1923: Keep the built-in observability implementations working","message":"PYCBC-1923: Keep the built-in observability implementations working\n\nChanges\n--------\n* LoggingMeter.create_report read each service\u0027s recorders with\n  ConcurrentMap.flush(), which does not copy, it detaches: it swaps in a\n  fresh dict and returns the old one.  On its own that would only lose\n  the registration, because value_recorder calls get_or_create.  It does\n  not, because _recorder_cache keys recorders by (service, operation)\n  and short circuits ahead of get_or_create.  So every operation after\n  the first report recorded into a LoggingValueRecorder no longer\n  reachable from self._recorders, and create_report never visited it\n  again.  A process configured with LoggingMeter logged exactly one\n  report and then went silent for its lifetime.  Iterate with items()\n  instead, which leaves the recorders registered\n* flush() was correct when value_recorder went through the map on\n  every call: detaching it meant the next call rebuilt the recorder in\n  the fresh map.  _recorder_cache holds the recorder directly, so the\n  write path stopped consulting the map and the detach no longer\n  rebuilds anything.  The contract broke, not the method\n* Keeping flush() would have meant invalidating _recorder_cache in the\n  same step, and that cache is deliberately lock-free.  Its own comment\n  reasons that two threads racing the slow path write the same value,\n  which holds only because entries are never removed.  Add removal and\n  a reader can take an entry pointing at a recorder that has just been\n  detached; the value it records is then lost rather than deferred,\n  because nothing reports that recorder again.  Closing the window\n  needs a lock on the per-operation path, which is what the cache\n  exists to avoid.  Iterating has no such window: a late write lands\n  in a registered recorder and is counted next interval\n* Iterating makes the recorders permanent, which is the cost of this\n  approach and is bounded by the enums.  Eight services and 146\n  operations is 1168 recorders, measured at 1.2 MiB for the full set,\n  and any real workload touches a small fraction of it\n* The flush was not needed for interval accounting either:\n  LoggingValueRecorder.get_percentiles_and_reset already resets the\n  underlying histogram, so each report still covers only its own\n  interval.  Measured across three consecutive reports.  flush() was\n  doing two jobs and only the unregistering one was unique to it,\n  which is the job that was wrong\n* Guard the per-operation entry on total_count rather than on the\n  report\u0027s truthiness.  get_percentiles_and_reset returns a two-key\n  dict whatever it finds, so `if percentile_report:` was always true and\n  did not do what it reads as.  That did not matter while flush()\n  removed idle recorders from the map; with items() it does, and without\n  this an idle interval would report a zero-valued entry for every\n  operation the process has ever performed\n* NoOpTracer.request_span returned NoOpSpan(), but NoOpSpan.__init__\n  takes name as a required positional parameter, so the call raised\n  TypeError: __init__() missing 1 required positional argument: \u0027name\u0027.\n  NoOpTracer is how tracing is turned off, so tracing could not be\n  disabled on any path that creates a span.  Forward what the caller\n  passed instead, including the parent_span and start_time that were\n  being dropped\n* Widen NoOpSpan.__init__\u0027s parent_span to Optional[RequestSpan] to\n  match what request_span accepts.  Forwarding an Optional[RequestSpan]\n  into a parameter declared Optional[NoOpSpan] is the one type error the\n  fix would otherwise introduce, and NoOpSpan discards the argument\n* ClusterImpl.close_connection stopped the tracer\u0027s reporter and never\n  the meter\u0027s.  LoggingMeter.close() exists and stops its reporter, and\n  nothing outside the tests called it, so a closed cluster kept a\n  LoggingMeterReporter alive and emitting.  Add the meter branch beside\n  the tracer branch\n* AsyncClusterImpl.close_connection had the same gap and one more: it\n  read self._cluster_settings.tracer.tracer where the synchronous path\n  reads .observability_instruments.tracer.tracer.  ClusterSettings is a\n  dataclass with an observability_instruments field and no tracer field,\n  so the read raised AttributeError inside a try whose except Exception\n  swallowed it, and the asynchronous path stopped neither reporter.\n  txcouchbase inherits this through close_connection_deferred\n* Both instruments are installed by default, so neither leak needed a\n  configured cluster to reproduce.  Both reporter threads set daemon,\n  so the process still exits; the cost is a reporter per cluster that\n  keeps running and emitting after close, accumulating across open and\n  close cycles.  Measured against 7.6.10 with default ClusterOptions:\n  one leaked thread per cycle synchronously and two asynchronously,\n  zero either way with this applied\n* Add test_reports_every_interval to the LoggingMeter suite and a\n  no-op tracer suite in couchbase/tests/no_op_observability_t.py.  All\n  three fail against the unfixed tree and need no cluster.  The existing\n  test_reset_after_report already pins the idle-interval behavior and\n  still passes, which is what the total_count guard preserves\n* Remove ConcurrentMap.flush().  Nothing calls it once create_report\n  iterates, and the class is private to this module: it is neither\n  exported nor named anywhere else in couchbase, acouchbase or\n  txcouchbase, tests included.  Leaving it would leave the trap that\n  caused this defect sitting beside the code that fell into it\n* Record at _recorder_cache why self._recorders may not be replaced.\n  The cache is what pins the recorders, so the constraint belongs with\n  the thing that imposes it rather than with the loop that has to\n  respect it\n* The bare except Exception in the shutdown path is what hid the\n  asynchronous defect from every test.  Narrowing it would change\n  behavior on unrelated shutdown errors, so it is left alone here\n\nChange-Id: Iff6addc219263e7020ec86a96b80509c4fe98e17\n"},"parents_data":[{"branch_name":"refs/heads/master","commit_id":"9e7ee02fc137011195ddf2c3c4b0b46b1eaa77cb","is_merged_in_target_branch":false,"change_id":"I66ebfae732ef17a3a1a175e1524589ef5e9caa33","change_number":251906,"patch_set_number":3,"change_status":"MERGED"}],"branch":"refs/heads/master","description":"Rebase"},"d196673e41082aafb28cd28765d7af581090c017":{"kind":"NO_CODE_CHANGE","_number":3,"created":"2026-08-28 18:00:01.000000000","uploader":{"_account_id":1004568,"name":"Jared Casey","email":"jared.casey@couchbase.com","username":"thejcfactor","avatars":[{"url":"https://www.gravatar.com/avatar/20ac69da8a1fb4cc11bdd1c880389132.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d32","height":32},{"url":"https://www.gravatar.com/avatar/20ac69da8a1fb4cc11bdd1c880389132.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d56","height":56},{"url":"https://www.gravatar.com/avatar/20ac69da8a1fb4cc11bdd1c880389132.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d100","height":100},{"url":"https://www.gravatar.com/avatar/20ac69da8a1fb4cc11bdd1c880389132.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d120","height":120}]},"ref":"refs/changes/39/251939/3","fetch":{"anonymous http":{"url":"https://review.couchbase.org/couchbase-python-client","ref":"refs/changes/39/251939/3","commands":{"Branch":"git fetch https://review.couchbase.org/couchbase-python-client refs/changes/39/251939/3 \u0026\u0026 git checkout -b change-251939 FETCH_HEAD","Checkout":"git fetch https://review.couchbase.org/couchbase-python-client refs/changes/39/251939/3 \u0026\u0026 git checkout FETCH_HEAD","Cherry Pick":"git fetch https://review.couchbase.org/couchbase-python-client refs/changes/39/251939/3 \u0026\u0026 git cherry-pick FETCH_HEAD","Format Patch":"git fetch https://review.couchbase.org/couchbase-python-client refs/changes/39/251939/3 \u0026\u0026 git format-patch -1 --stdout FETCH_HEAD","Pull":"git pull https://review.couchbase.org/couchbase-python-client refs/changes/39/251939/3","Reset To":"git fetch https://review.couchbase.org/couchbase-python-client refs/changes/39/251939/3 \u0026\u0026 git reset --hard FETCH_HEAD"}}},"commit":{"parents":[{"commit":"61a7b50876bbc80bb015d71e826e58e8b2574c3c","subject":"PYCBC-1895: Correct the variadic options annotations on query methods"}],"author":{"name":"Jared Casey","email":"jared.casey@couchbase.com","date":"2026-08-27 22:27:12.000000000","tz":-360},"committer":{"name":"Jared Casey","email":"jared.casey@couchbase.com","date":"2026-08-28 18:00:01.000000000","tz":0},"subject":"PYCBC-1923: Keep the built-in observability implementations working","message":"PYCBC-1923: Keep the built-in observability implementations working\n\nChanges\n--------\n* LoggingMeter.create_report read each service\u0027s recorders with\n  ConcurrentMap.flush(), which does not copy, it detaches: it swaps in a\n  fresh dict and returns the old one.  On its own that would only lose\n  the registration, because value_recorder calls get_or_create.  It does\n  not, because _recorder_cache keys recorders by (service, operation)\n  and short circuits ahead of get_or_create.  So every operation after\n  the first report recorded into a LoggingValueRecorder no longer\n  reachable from self._recorders, and create_report never visited it\n  again.  A process configured with LoggingMeter logged exactly one\n  report and then went silent for its lifetime.  Iterate with items()\n  instead, which leaves the recorders registered\n* flush() was correct when value_recorder went through the map on\n  every call: detaching it meant the next call rebuilt the recorder in\n  the fresh map.  _recorder_cache holds the recorder directly, so the\n  write path stopped consulting the map and the detach no longer\n  rebuilds anything.  The contract broke, not the method\n* Keeping flush() would have meant invalidating _recorder_cache in the\n  same step, and that cache is deliberately lock-free.  Its own comment\n  reasons that two threads racing the slow path write the same value,\n  which holds only because entries are never removed.  Add removal and\n  a reader can take an entry pointing at a recorder that has just been\n  detached; the value it records is then lost rather than deferred,\n  because nothing reports that recorder again.  Closing the window\n  needs a lock on the per-operation path, which is what the cache\n  exists to avoid.  Iterating has no such window: a late write lands\n  in a registered recorder and is counted next interval\n* Iterating makes the recorders permanent, which is the cost of this\n  approach and is bounded by the enums.  Eight services and 146\n  operations is 1168 recorders, measured at 1.2 MiB for the full set,\n  and any real workload touches a small fraction of it\n* The flush was not needed for interval accounting either:\n  LoggingValueRecorder.get_percentiles_and_reset already resets the\n  underlying histogram, so each report still covers only its own\n  interval.  Measured across three consecutive reports.  flush() was\n  doing two jobs and only the unregistering one was unique to it,\n  which is the job that was wrong\n* Guard the per-operation entry on total_count rather than on the\n  report\u0027s truthiness.  get_percentiles_and_reset returns a two-key\n  dict whatever it finds, so `if percentile_report:` was always true and\n  did not do what it reads as.  That did not matter while flush()\n  removed idle recorders from the map; with items() it does, and without\n  this an idle interval would report a zero-valued entry for every\n  operation the process has ever performed\n* NoOpTracer.request_span returned NoOpSpan(), but NoOpSpan.__init__\n  takes name as a required positional parameter, so the call raised\n  TypeError: __init__() missing 1 required positional argument: \u0027name\u0027.\n  NoOpTracer is how tracing is turned off, so tracing could not be\n  disabled on any path that creates a span.  Forward what the caller\n  passed instead, including the parent_span and start_time that were\n  being dropped\n* Widen NoOpSpan.__init__\u0027s parent_span to Optional[RequestSpan] to\n  match what request_span accepts.  Forwarding an Optional[RequestSpan]\n  into a parameter declared Optional[NoOpSpan] is the one type error the\n  fix would otherwise introduce, and NoOpSpan discards the argument\n* ClusterImpl.close_connection stopped the tracer\u0027s reporter and never\n  the meter\u0027s.  LoggingMeter.close() exists and stops its reporter, and\n  nothing outside the tests called it, so a closed cluster kept a\n  LoggingMeterReporter alive and emitting.  Add the meter branch beside\n  the tracer branch\n* AsyncClusterImpl.close_connection had the same gap and one more: it\n  read self._cluster_settings.tracer.tracer where the synchronous path\n  reads .observability_instruments.tracer.tracer.  ClusterSettings is a\n  dataclass with an observability_instruments field and no tracer field,\n  so the read raised AttributeError inside a try whose except Exception\n  swallowed it, and the asynchronous path stopped neither reporter.\n  txcouchbase inherits this through close_connection_deferred\n* Both instruments are installed by default, so neither leak needed a\n  configured cluster to reproduce.  Both reporter threads set daemon,\n  so the process still exits; the cost is a reporter per cluster that\n  keeps running and emitting after close, accumulating across open and\n  close cycles.  Measured against 7.6.10 with default ClusterOptions:\n  one leaked thread per cycle synchronously and two asynchronously,\n  zero either way with this applied\n* Add test_reports_every_interval to the LoggingMeter suite and a\n  no-op tracer suite in couchbase/tests/no_op_observability_t.py.  All\n  three fail against the unfixed tree and need no cluster.  The existing\n  test_reset_after_report already pins the idle-interval behavior and\n  still passes, which is what the total_count guard preserves\n* Remove ConcurrentMap.flush().  Nothing calls it once create_report\n  iterates, and the class is private to this module: it is neither\n  exported nor named anywhere else in couchbase, acouchbase or\n  txcouchbase, tests included.  Leaving it would leave the trap that\n  caused this defect sitting beside the code that fell into it\n* Record at _recorder_cache why self._recorders may not be replaced.\n  The cache is what pins the recorders, so the constraint belongs with\n  the thing that imposes it rather than with the loop that has to\n  respect it\n* The bare except Exception in the shutdown path is what hid the\n  asynchronous defect from every test.  Narrowing it would change\n  behavior on unrelated shutdown errors, so it is left alone here\n\nChange-Id: Iff6addc219263e7020ec86a96b80509c4fe98e17\nReviewed-on: https://review.couchbase.org/c/couchbase-python-client/+/251939\nReviewed-by: Dimitris Christodoulou \u003cdimitris.christodoulou@couchbase.com\u003e\nTested-by: Build Bot \u003cbuild@couchbase.com\u003e\n"},"parents_data":[{"branch_name":"refs/heads/master","commit_id":"61a7b50876bbc80bb015d71e826e58e8b2574c3c","is_merged_in_target_branch":true,"change_id":"I66ebfae732ef17a3a1a175e1524589ef5e9caa33","change_number":251906,"patch_set_number":4,"change_status":"MERGED"}],"branch":"refs/heads/master"}},"requirements":[],"submit_records":[{"rule_name":"gerrit~DefaultSubmitRule","status":"CLOSED","labels":[{"label":"Verified","status":"OK","applied_by":{"_account_id":1000011,"name":"Build Bot","email":"build@couchbase.com","username":"buildbot","avatars":[{"url":"https://www.gravatar.com/avatar/0ba35a43c05d6329d9b2136bab05a733.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d32","height":32},{"url":"https://www.gravatar.com/avatar/0ba35a43c05d6329d9b2136bab05a733.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d56","height":56},{"url":"https://www.gravatar.com/avatar/0ba35a43c05d6329d9b2136bab05a733.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d100","height":100},{"url":"https://www.gravatar.com/avatar/0ba35a43c05d6329d9b2136bab05a733.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d120","height":120}],"tags":["SERVICE_USER"]}},{"label":"Code-Review","status":"OK","applied_by":{"_account_id":1005035,"name":"Dimitris Christodoulou","email":"dimitris.christodoulou@couchbase.com","username":"DemetrisChr","avatars":[{"url":"https://www.gravatar.com/avatar/4291f7baa025a5558b77019a9c264ab2.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d32","height":32},{"url":"https://www.gravatar.com/avatar/4291f7baa025a5558b77019a9c264ab2.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d56","height":56},{"url":"https://www.gravatar.com/avatar/4291f7baa025a5558b77019a9c264ab2.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d100","height":100},{"url":"https://www.gravatar.com/avatar/4291f7baa025a5558b77019a9c264ab2.jpg?d\u003didenticon\u0026r\u003dpg\u0026s\u003d120","height":120}]}},{"label":"Well-Formed","status":"MAY"}]}],"submit_requirements":[{"name":"Verified","status":"SATISFIED","is_legacy":true,"submittability_expression_result":{"expression":"label:Verified\u003dMAX -label:Verified\u003dMIN","fulfilled":true,"status":"PASS","passing_atoms":["label:Verified\u003dMAX","-label:Verified\u003dMIN"],"failing_atoms":[]}},{"name":"Code-Review","status":"SATISFIED","is_legacy":true,"submittability_expression_result":{"expression":"label:Code-Review\u003dMAX -label:Code-Review\u003dMIN","fulfilled":true,"status":"PASS","passing_atoms":["label:Code-Review\u003dMAX","-label:Code-Review\u003dMIN"],"failing_atoms":[]}}]}
