Fix reporting for Administrator Commissioning attributes. (#23589)

* Fix reporting for Administrator Commissioning attributes.

Nothing was marking the attributes dirty when the data backing them changed.

* Remove the dependency of af-types.h from reporting.h, so reporting.h can be
  part of the SDK library, not the app.
* Move reporting.h to the same library as the other reporting files.
* Fix the one example app that was using the EmberAfAttributeType bits in
  reporting.h.
* Fix color control server depending on reporting.h to get af-types.h.
* Add convenience MakeNullable methods, like we have for Optional.
* Make sure we call MatterReportingAttributeChangeCallback as needed in
  CommissioningWindowManager.
* Add a unit test that fails without these changes.
* Fix the existing TestCommissioningWindow unit test to not hardcode fabric
  indices, since that's not needed anymore.

* Address review comment.
diff --git a/examples/bridge-app/linux/main.cpp b/examples/bridge-app/linux/main.cpp
index 5007cee..a1b54c5 100644
--- a/examples/bridge-app/linux/main.cpp
+++ b/examples/bridge-app/linux/main.cpp
@@ -420,9 +420,7 @@
 
     if (itemChangedMask & DevicePowerSource::kChanged_BatLevel)
     {
-        uint8_t batChargeLevel = dev->GetBatChargeLevel();
-        MatterReportingAttributeChangeCallback(dev->GetEndpointId(), PowerSource::Id, PowerSource::Attributes::BatChargeLevel::Id,
-                                               ZCL_INT8U_ATTRIBUTE_TYPE, &batChargeLevel);
+        MatterReportingAttributeChangeCallback(dev->GetEndpointId(), PowerSource::Id, PowerSource::Attributes::BatChargeLevel::Id);
     }
 
     if (itemChangedMask & DevicePowerSource::kChanged_Description)
diff --git a/src/app/BUILD.gn b/src/app/BUILD.gn
index 734baf6..83d6c7d 100644
--- a/src/app/BUILD.gn
+++ b/src/app/BUILD.gn
@@ -183,6 +183,7 @@
     "WriteHandler.cpp",
     "reporting/Engine.cpp",
     "reporting/Engine.h",
+    "reporting/reporting.h",
   ]
 
   public_deps = [
diff --git a/src/app/chip_data_model.gni b/src/app/chip_data_model.gni
index da193e7..8eaecc3 100644
--- a/src/app/chip_data_model.gni
+++ b/src/app/chip_data_model.gni
@@ -94,7 +94,6 @@
       "${_app_root}/clusters/on-off-server/on-off-server.h",
       "${_app_root}/clusters/scenes/scenes-tokens.h",
       "${_app_root}/clusters/scenes/scenes.h",
-      "${_app_root}/reporting/reporting.h",
       "${_app_root}/util/DataModelHandler.cpp",
       "${_app_root}/util/af-event.cpp",
       "${_app_root}/util/attribute-size-util.cpp",
diff --git a/src/app/clusters/color-control-server/color-control-server.h b/src/app/clusters/color-control-server/color-control-server.h
index 32ac777..22cb14e 100644
--- a/src/app/clusters/color-control-server/color-control-server.h
+++ b/src/app/clusters/color-control-server/color-control-server.h
@@ -19,7 +19,7 @@
 
 #include <app-common/zap-generated/cluster-objects.h>
 #include <app/ConcreteCommandPath.h>
-#include <app/reporting/reporting.h>
+#include <app/util/af-types.h>
 #include <app/util/basic-types.h>
 
 /**********************************************************
diff --git a/src/app/data-model/Nullable.h b/src/app/data-model/Nullable.h
index c0e2a7e..46586e0 100644
--- a/src/app/data-model/Nullable.h
+++ b/src/app/data-model/Nullable.h
@@ -86,6 +86,18 @@
     bool operator!=(const Nullable & other) const { return !(*this == other); }
 };
 
+template <class T>
+constexpr Nullable<std::decay_t<T>> MakeNullable(T && value)
+{
+    return Nullable<std::decay_t<T>>(InPlace, std::forward<T>(value));
+}
+
+template <class T, class... Args>
+constexpr Nullable<T> MakeNullable(Args &&... args)
+{
+    return Nullable<T>(InPlace, std::forward<Args>(args)...);
+}
+
 } // namespace DataModel
 } // namespace app
 } // namespace chip
diff --git a/src/app/reporting/Engine.cpp b/src/app/reporting/Engine.cpp
index e4dcdfc..6e25f59 100644
--- a/src/app/reporting/Engine.cpp
+++ b/src/app/reporting/Engine.cpp
@@ -964,3 +964,10 @@
 
 void __attribute__((weak)) MatterPreAttributeReadCallback(const chip::app::ConcreteAttributePath & attributePath) {}
 void __attribute__((weak)) MatterPostAttributeReadCallback(const chip::app::ConcreteAttributePath & attributePath) {}
+
+// TODO: MatterReportingAttributeChangeCallback should just live in libCHIP,
+// instead of being in ember-compatibility-functions.  It does not depend on any
+// app-specific generated bits.
+void __attribute__((weak))
+MatterReportingAttributeChangeCallback(chip::EndpointId endpoint, chip::ClusterId clusterId, chip::AttributeId attributeId)
+{}
diff --git a/src/app/reporting/reporting.h b/src/app/reporting/reporting.h
index eaed8e8..02a8aec 100644
--- a/src/app/reporting/reporting.h
+++ b/src/app/reporting/reporting.h
@@ -18,20 +18,13 @@
 #pragma once
 
 #include <app/ConcreteAttributePath.h>
-#include <app/util/af-types.h>
 
 /** @brief Reporting Attribute Change
  *
  * This function is called by the framework when an attribute managed by the
  * framework changes.  The application should call this function when an
- * externally-managed attribute changes.  The application should use the change
- * notification to inform its reporting decisions.
- */
-void MatterReportingAttributeChangeCallback(chip::EndpointId endpoint, chip::ClusterId clusterId, chip::AttributeId attributeId,
-                                            EmberAfAttributeType type, uint8_t * data);
-
-/*
- * Same but with just an attribute path and no data available.
+ * externally-managed attribute changes.  This function triggers attribute
+ * reports for subscriptions as needed.
  */
 void MatterReportingAttributeChangeCallback(chip::EndpointId endpoint, chip::ClusterId clusterId, chip::AttributeId attributeId);
 
diff --git a/src/app/server/CommissioningWindowManager.cpp b/src/app/server/CommissioningWindowManager.cpp
index 4256f9b..949b460 100644
--- a/src/app/server/CommissioningWindowManager.cpp
+++ b/src/app/server/CommissioningWindowManager.cpp
@@ -15,6 +15,7 @@
  *    limitations under the License.
  */
 
+#include <app/reporting/reporting.h>
 #include <app/server/CommissioningWindowManager.h>
 #include <app/server/Dnssd.h>
 #include <app/server/Server.h>
@@ -28,6 +29,9 @@
 using namespace chip::System::Clock;
 
 using AdministratorCommissioning::CommissioningWindowStatus;
+using chip::app::DataModel::MakeNullable;
+using chip::app::DataModel::Nullable;
+using chip::app::DataModel::NullNullable;
 
 namespace {
 
@@ -93,10 +97,11 @@
     mECMDiscriminator = 0;
     mECMIterations    = 0;
     mECMSaltLength    = 0;
-    mWindowStatus     = CommissioningWindowStatus::kWindowNotOpen;
 
-    mOpenerFabricIndex.SetNull();
-    mOpenerVendorId.SetNull();
+    UpdateWindowStatus(CommissioningWindowStatus::kWindowNotOpen);
+
+    UpdateOpenerFabricIndex(NullNullable);
+    UpdateOpenerVendorId(NullNullable);
 
     memset(&mECMPASEVerifier, 0, sizeof(mECMPASEVerifier));
     memset(mECMSalt, 0, sizeof(mECMSalt));
@@ -294,8 +299,8 @@
 {
     ReturnErrorOnFailure(OpenBasicCommissioningWindow(commissioningTimeout, CommissioningWindowAdvertisement::kDnssdOnly));
 
-    mOpenerFabricIndex.SetNonNull(fabricIndex);
-    mOpenerVendorId.SetNonNull(vendorId);
+    UpdateOpenerFabricIndex(MakeNullable(fabricIndex));
+    UpdateOpenerVendorId(MakeNullable(vendorId));
 
     return CHIP_NO_ERROR;
 }
@@ -329,8 +334,8 @@
     }
     else
     {
-        mOpenerFabricIndex.SetNonNull(fabricIndex);
-        mOpenerVendorId.SetNonNull(vendorId);
+        UpdateOpenerFabricIndex(MakeNullable(fabricIndex));
+        UpdateOpenerVendorId(MakeNullable(vendorId));
     }
 
     return err;
@@ -356,6 +361,10 @@
 
 CommissioningWindowStatus CommissioningWindowManager::CommissioningWindowStatusForCluster() const
 {
+    // If the condition we use to determine whether we were opened via the
+    // cluster ever changes, make sure whatever code affects that condition
+    // marks calls MatterReportingAttributeChangeCallback for WindowStatus as
+    // needed.
     if (mOpenerVendorId.IsNull())
     {
         // Not opened via the cluster.
@@ -375,7 +384,7 @@
     if (!mOpenerFabricIndex.IsNull() && mOpenerFabricIndex.Value() == removedIndex)
     {
         // Per spec, we should clear out the stale fabric index.
-        mOpenerFabricIndex.SetNull();
+        UpdateOpenerFabricIndex(NullNullable);
     }
 }
 
@@ -424,11 +433,11 @@
 
     if (mUseECM)
     {
-        mWindowStatus = CommissioningWindowStatus::kEnhancedWindowOpen;
+        UpdateWindowStatus(CommissioningWindowStatus::kEnhancedWindowOpen);
     }
     else
     {
-        mWindowStatus = CommissioningWindowStatus::kBasicWindowOpen;
+        UpdateWindowStatus(CommissioningWindowStatus::kBasicWindowOpen);
     }
 
     if (mAppDelegate != nullptr)
@@ -526,4 +535,51 @@
     }
 }
 
+void CommissioningWindowManager::UpdateWindowStatus(CommissioningWindowStatus aNewStatus)
+{
+    CommissioningWindowStatus oldClusterStatus = CommissioningWindowStatusForCluster();
+    mWindowStatus                              = aNewStatus;
+    if (CommissioningWindowStatusForCluster() != oldClusterStatus)
+    {
+        // The Administrator Commissioning cluster is always on the root endpoint.
+        MatterReportingAttributeChangeCallback(kRootEndpointId, AdministratorCommissioning::Id,
+                                               AdministratorCommissioning::Attributes::WindowStatus::Id);
+    }
+}
+
+void CommissioningWindowManager::UpdateOpenerVendorId(Nullable<VendorId> aNewOpenerVendorId)
+{
+    // Changing the opener vendor id affects what
+    // CommissioningWindowStatusForCluster() returns.
+    CommissioningWindowStatus oldClusterStatus = CommissioningWindowStatusForCluster();
+
+    if (mOpenerVendorId != aNewOpenerVendorId)
+    {
+        // The Administrator Commissioning cluster is always on the root endpoint.
+        MatterReportingAttributeChangeCallback(kRootEndpointId, AdministratorCommissioning::Id,
+                                               AdministratorCommissioning::Attributes::AdminVendorId::Id);
+    }
+
+    mOpenerVendorId = aNewOpenerVendorId;
+
+    if (CommissioningWindowStatusForCluster() != oldClusterStatus)
+    {
+        // The Administrator Commissioning cluster is always on the root endpoint.
+        MatterReportingAttributeChangeCallback(kRootEndpointId, AdministratorCommissioning::Id,
+                                               AdministratorCommissioning::Attributes::WindowStatus::Id);
+    }
+}
+
+void CommissioningWindowManager::UpdateOpenerFabricIndex(Nullable<FabricIndex> aNewOpenerFabricIndex)
+{
+    if (mOpenerFabricIndex != aNewOpenerFabricIndex)
+    {
+        // The Administrator Commissioning cluster is always on the root endpoint.
+        MatterReportingAttributeChangeCallback(kRootEndpointId, AdministratorCommissioning::Id,
+                                               AdministratorCommissioning::Attributes::AdminFabricIndex::Id);
+    }
+
+    mOpenerFabricIndex = aNewOpenerFabricIndex;
+}
+
 } // namespace chip
diff --git a/src/app/server/CommissioningWindowManager.h b/src/app/server/CommissioningWindowManager.h
index 9381a2c..bb2cf00 100644
--- a/src/app/server/CommissioningWindowManager.h
+++ b/src/app/server/CommissioningWindowManager.h
@@ -171,6 +171,14 @@
      */
     void ExpireFailSafeIfArmed();
 
+    /**
+     * Helpers to ensure the right attribute reporting happens when our state is
+     * updated.
+     */
+    void UpdateWindowStatus(app::Clusters::AdministratorCommissioning::CommissioningWindowStatus aNewStatus);
+    void UpdateOpenerVendorId(app::DataModel::Nullable<VendorId> aNewOpenerVendorId);
+    void UpdateOpenerFabricIndex(app::DataModel::Nullable<FabricIndex> aNewOpenerFabricIndex);
+
     AppDelegate * mAppDelegate = nullptr;
     Server * mServer           = nullptr;
 
diff --git a/src/app/tests/TestCommissionManager.cpp b/src/app/tests/TestCommissionManager.cpp
index 580b62e..7a05cbd 100644
--- a/src/app/tests/TestCommissionManager.cpp
+++ b/src/app/tests/TestCommissionManager.cpp
@@ -38,6 +38,45 @@
 void InitDataModelHandler(chip::Messaging::ExchangeManager * exchangeMgr) {}
 
 namespace {
+bool sAdminFabricIndexDirty = false;
+bool sAdminVendorIdDirty    = false;
+bool sWindowStatusDirty     = false;
+
+void ResetDirtyFlags()
+{
+    sAdminFabricIndexDirty = false;
+    sAdminVendorIdDirty    = false;
+    sWindowStatusDirty     = false;
+}
+
+} // namespace
+
+void MatterReportingAttributeChangeCallback(chip::EndpointId endpoint, chip::ClusterId clusterId, chip::AttributeId attributeId)
+{
+    using namespace chip::app::Clusters;
+    using namespace chip::app::Clusters::AdministratorCommissioning::Attributes;
+    if (endpoint != chip::kRootEndpointId || clusterId != AdministratorCommissioning::Id)
+    {
+        return;
+    }
+
+    switch (attributeId)
+    {
+    case WindowStatus::Id:
+        sWindowStatusDirty = true;
+        break;
+    case AdminVendorId::Id:
+        sAdminVendorIdDirty = true;
+        break;
+    case AdminFabricIndex::Id:
+        sAdminFabricIndexDirty = true;
+        break;
+    default:
+        break;
+    }
+}
+
+namespace {
 
 static constexpr int kTestTaskWaitSeconds = 2;
 
@@ -85,7 +124,11 @@
 
 void CheckCommissioningWindowManagerBasicWindowOpenCloseTask(intptr_t context)
 {
-    nlTestSuite * suite                        = reinterpret_cast<nlTestSuite *>(context);
+    nlTestSuite * suite = reinterpret_cast<nlTestSuite *>(context);
+    NL_TEST_ASSERT(suite, !sWindowStatusDirty);
+    NL_TEST_ASSERT(suite, !sAdminFabricIndexDirty);
+    NL_TEST_ASSERT(suite, !sAdminVendorIdDirty);
+
     CommissioningWindowManager & commissionMgr = Server::GetInstance().GetCommissioningWindowManager();
     CHIP_ERROR err                             = commissionMgr.OpenBasicCommissioningWindow(commissionMgr.MaxCommissioningTimeout(),
                                                                 CommissioningWindowAdvertisement::kDnssdOnly);
@@ -97,8 +140,15 @@
     NL_TEST_ASSERT(suite, commissionMgr.GetOpenerFabricIndex().IsNull());
     NL_TEST_ASSERT(suite, commissionMgr.GetOpenerVendorId().IsNull());
     NL_TEST_ASSERT(suite, !chip::DeviceLayer::ConnectivityMgr().IsBLEAdvertisingEnabled());
+    NL_TEST_ASSERT(suite, !sWindowStatusDirty);
+    NL_TEST_ASSERT(suite, !sAdminFabricIndexDirty);
+    NL_TEST_ASSERT(suite, !sAdminVendorIdDirty);
+
     commissionMgr.CloseCommissioningWindow();
     NL_TEST_ASSERT(suite, !commissionMgr.IsCommissioningWindowOpen());
+    NL_TEST_ASSERT(suite, !sWindowStatusDirty);
+    NL_TEST_ASSERT(suite, !sAdminFabricIndexDirty);
+    NL_TEST_ASSERT(suite, !sAdminVendorIdDirty);
 }
 
 void CheckCommissioningWindowManagerBasicWindowOpenClose(nlTestSuite * suite, void *)
@@ -110,7 +160,11 @@
 
 void CheckCommissioningWindowManagerBasicWindowOpenCloseFromClusterTask(intptr_t context)
 {
-    nlTestSuite * suite                        = reinterpret_cast<nlTestSuite *>(context);
+    nlTestSuite * suite = reinterpret_cast<nlTestSuite *>(context);
+    NL_TEST_ASSERT(suite, !sWindowStatusDirty);
+    NL_TEST_ASSERT(suite, !sAdminFabricIndexDirty);
+    NL_TEST_ASSERT(suite, !sAdminVendorIdDirty);
+
     CommissioningWindowManager & commissionMgr = Server::GetInstance().GetCommissioningWindowManager();
     constexpr auto fabricIndex                 = static_cast<chip::FabricIndex>(1);
     constexpr auto vendorId                    = static_cast<chip::VendorId>(0xFFF3);
@@ -126,10 +180,24 @@
     NL_TEST_ASSERT(suite, !commissionMgr.GetOpenerVendorId().IsNull());
     NL_TEST_ASSERT(suite, commissionMgr.GetOpenerVendorId().Value() == vendorId);
     NL_TEST_ASSERT(suite, !chip::DeviceLayer::ConnectivityMgr().IsBLEAdvertisingEnabled());
+    NL_TEST_ASSERT(suite, sWindowStatusDirty);
+    NL_TEST_ASSERT(suite, sAdminFabricIndexDirty);
+    NL_TEST_ASSERT(suite, sAdminVendorIdDirty);
+
+    ResetDirtyFlags();
+    NL_TEST_ASSERT(suite, !sWindowStatusDirty);
+    NL_TEST_ASSERT(suite, !sAdminFabricIndexDirty);
+    NL_TEST_ASSERT(suite, !sAdminVendorIdDirty);
+
     commissionMgr.CloseCommissioningWindow();
     NL_TEST_ASSERT(suite, !commissionMgr.IsCommissioningWindowOpen());
     NL_TEST_ASSERT(suite, commissionMgr.GetOpenerFabricIndex().IsNull());
     NL_TEST_ASSERT(suite, commissionMgr.GetOpenerVendorId().IsNull());
+    NL_TEST_ASSERT(suite, sWindowStatusDirty);
+    NL_TEST_ASSERT(suite, sAdminFabricIndexDirty);
+    NL_TEST_ASSERT(suite, sAdminVendorIdDirty);
+
+    ResetDirtyFlags();
 }
 
 void CheckCommissioningWindowManagerBasicWindowOpenCloseFromCluster(nlTestSuite * suite, void *)
@@ -147,11 +215,18 @@
     NL_TEST_ASSERT(suite,
                    commissionMgr.CommissioningWindowStatusForCluster() ==
                        chip::app::Clusters::AdministratorCommissioning::CommissioningWindowStatus::kWindowNotOpen);
+    NL_TEST_ASSERT(suite, !sWindowStatusDirty);
+    NL_TEST_ASSERT(suite, !sAdminFabricIndexDirty);
+    NL_TEST_ASSERT(suite, !sAdminVendorIdDirty);
 }
 
 void CheckCommissioningWindowManagerWindowTimeoutTask(intptr_t context)
 {
-    nlTestSuite * suite                        = reinterpret_cast<nlTestSuite *>(context);
+    nlTestSuite * suite = reinterpret_cast<nlTestSuite *>(context);
+    NL_TEST_ASSERT(suite, !sWindowStatusDirty);
+    NL_TEST_ASSERT(suite, !sAdminFabricIndexDirty);
+    NL_TEST_ASSERT(suite, !sAdminVendorIdDirty);
+
     CommissioningWindowManager & commissionMgr = Server::GetInstance().GetCommissioningWindowManager();
     constexpr auto kTimeoutSeconds             = chip::System::Clock::Seconds16(1);
     constexpr uint16_t kTimeoutMs              = 1000;
@@ -164,6 +239,10 @@
                    commissionMgr.CommissioningWindowStatusForCluster() ==
                        chip::app::Clusters::AdministratorCommissioning::CommissioningWindowStatus::kWindowNotOpen);
     NL_TEST_ASSERT(suite, !chip::DeviceLayer::ConnectivityMgr().IsBLEAdvertisingEnabled());
+    NL_TEST_ASSERT(suite, !sWindowStatusDirty);
+    NL_TEST_ASSERT(suite, !sAdminFabricIndexDirty);
+    NL_TEST_ASSERT(suite, !sAdminVendorIdDirty);
+
     chip::DeviceLayer::SystemLayer().StartTimer(chip::System::Clock::Milliseconds32(kTimeoutMs + kSleepPadding),
                                                 CheckCommissioningWindowManagerWindowClosedTask, suite);
 }
@@ -183,17 +262,28 @@
     NL_TEST_ASSERT(suite,
                    commissionMgr.CommissioningWindowStatusForCluster() ==
                        chip::app::Clusters::AdministratorCommissioning::CommissioningWindowStatus::kWindowNotOpen);
+    NL_TEST_ASSERT(suite, !sWindowStatusDirty);
+    NL_TEST_ASSERT(suite, !sAdminFabricIndexDirty);
+    NL_TEST_ASSERT(suite, !sAdminVendorIdDirty);
+
     commissionMgr.OnSessionEstablishmentStarted();
     commissionMgr.OnSessionEstablishmentError(CHIP_ERROR_INTERNAL);
     NL_TEST_ASSERT(suite, commissionMgr.IsCommissioningWindowOpen());
     NL_TEST_ASSERT(suite,
                    commissionMgr.CommissioningWindowStatusForCluster() ==
                        chip::app::Clusters::AdministratorCommissioning::CommissioningWindowStatus::kWindowNotOpen);
+    NL_TEST_ASSERT(suite, !sWindowStatusDirty);
+    NL_TEST_ASSERT(suite, !sAdminFabricIndexDirty);
+    NL_TEST_ASSERT(suite, !sAdminVendorIdDirty);
 }
 
 void CheckCommissioningWindowManagerWindowTimeoutWithSessionEstablishmentErrorsTask(intptr_t context)
 {
-    nlTestSuite * suite                        = reinterpret_cast<nlTestSuite *>(context);
+    nlTestSuite * suite = reinterpret_cast<nlTestSuite *>(context);
+    NL_TEST_ASSERT(suite, !sWindowStatusDirty);
+    NL_TEST_ASSERT(suite, !sAdminFabricIndexDirty);
+    NL_TEST_ASSERT(suite, !sAdminVendorIdDirty);
+
     CommissioningWindowManager & commissionMgr = Server::GetInstance().GetCommissioningWindowManager();
     constexpr auto kTimeoutSeconds             = chip::System::Clock::Seconds16(1);
     constexpr uint16_t kTimeoutMs              = 1000;
@@ -205,10 +295,14 @@
                    commissionMgr.CommissioningWindowStatusForCluster() ==
                        chip::app::Clusters::AdministratorCommissioning::CommissioningWindowStatus::kWindowNotOpen);
     NL_TEST_ASSERT(suite, !chip::DeviceLayer::ConnectivityMgr().IsBLEAdvertisingEnabled());
+    NL_TEST_ASSERT(suite, !sWindowStatusDirty);
+    NL_TEST_ASSERT(suite, !sAdminFabricIndexDirty);
+    NL_TEST_ASSERT(suite, !sAdminVendorIdDirty);
+
     chip::DeviceLayer::SystemLayer().StartTimer(chip::System::Clock::Milliseconds32(kTimeoutMs + kSleepPadding),
                                                 CheckCommissioningWindowManagerWindowClosedTask, suite);
     // Simulate a session establishment error during that window, such that the
-    // delay for the error plust hte window size exceeds our "timeout + padding" above.
+    // delay for the error plus the window size exceeds our "timeout + padding" above.
     chip::DeviceLayer::SystemLayer().StartTimer(chip::System::Clock::Milliseconds32(kTimeoutMs / 4 * 3),
                                                 SimulateFailedSessionEstablishmentTask, suite);
 }
@@ -233,6 +327,10 @@
     uint8_t salt[chip::kSpake2p_Min_PBKDF_Salt_Length];
     chip::ByteSpan saltData(salt);
 
+    NL_TEST_ASSERT(suite, !sWindowStatusDirty);
+    NL_TEST_ASSERT(suite, !sAdminFabricIndexDirty);
+    NL_TEST_ASSERT(suite, !sAdminVendorIdDirty);
+
     constexpr auto fabricIndex = static_cast<chip::FabricIndex>(1);
     constexpr auto vendorId    = static_cast<chip::VendorId>(0xFFF3);
     err = commissionMgr.OpenEnhancedCommissioningWindow(commissionMgr.MaxCommissioningTimeout(), newDiscriminator, verifier,
@@ -247,6 +345,14 @@
     NL_TEST_ASSERT(suite, commissionMgr.GetOpenerFabricIndex().Value() == fabricIndex);
     NL_TEST_ASSERT(suite, !commissionMgr.GetOpenerVendorId().IsNull());
     NL_TEST_ASSERT(suite, commissionMgr.GetOpenerVendorId().Value() == vendorId);
+    NL_TEST_ASSERT(suite, sWindowStatusDirty);
+    NL_TEST_ASSERT(suite, sAdminFabricIndexDirty);
+    NL_TEST_ASSERT(suite, sAdminVendorIdDirty);
+
+    ResetDirtyFlags();
+    NL_TEST_ASSERT(suite, !sWindowStatusDirty);
+    NL_TEST_ASSERT(suite, !sAdminFabricIndexDirty);
+    NL_TEST_ASSERT(suite, !sAdminVendorIdDirty);
 
     commissionMgr.CloseCommissioningWindow();
     NL_TEST_ASSERT(suite, !commissionMgr.IsCommissioningWindowOpen());
@@ -255,6 +361,11 @@
                        chip::app::Clusters::AdministratorCommissioning::CommissioningWindowStatus::kWindowNotOpen);
     NL_TEST_ASSERT(suite, commissionMgr.GetOpenerFabricIndex().IsNull());
     NL_TEST_ASSERT(suite, commissionMgr.GetOpenerVendorId().IsNull());
+    NL_TEST_ASSERT(suite, sWindowStatusDirty);
+    NL_TEST_ASSERT(suite, sAdminFabricIndexDirty);
+    NL_TEST_ASSERT(suite, sAdminVendorIdDirty);
+
+    ResetDirtyFlags();
 }
 
 void CheckCommissioningWindowManagerEnhancedWindow(nlTestSuite * suite, void *)
diff --git a/src/app/tests/suites/TestCommissioningWindow.yaml b/src/app/tests/suites/TestCommissioningWindow.yaml
index bade4a2..5ec5bc4 100644
--- a/src/app/tests/suites/TestCommissioningWindow.yaml
+++ b/src/app/tests/suites/TestCommissioningWindow.yaml
@@ -27,12 +27,6 @@
     payload:
         type: char_string
         defaultValue: "MT:-24J0AFN00KA0648G00" # This value needs to be generated automatically
-    alphaIndex:
-        type: int8u
-        defaultValue: 1
-    betaIndex:
-        type: int8u
-        defaultValue: 2
 
 tests:
     - label: "Wait for the commissioned device to be retrieved for alpha"
@@ -48,10 +42,7 @@
       command: "readAttribute"
       attribute: "CurrentFabricIndex"
       response:
-          # We could saveAs here, but then when we try to compare to it later
-          # the nullable-vs-non-nullable compare fails to work right.  For now
-          # just use a config variable.
-          value: alphaIndex
+          saveAs: alphaIndex
 
     - label: "Check that commissioning window is not open"
       command: "readAttribute"
@@ -172,10 +163,7 @@
       command: "readAttribute"
       attribute: "CurrentFabricIndex"
       response:
-          # We could saveAs here, but then when we try to compare to it later
-          # the nullable-vs-non-nullable compare fails to work right.  For now
-          # just use a config variable.
-          value: betaIndex
+          saveAs: betaIndex
 
     - label: "Open Commissioning Window from beta"
       identity: "beta"
diff --git a/src/app/tests/suites/TestSubscribe_AdministratorCommissioning.yaml b/src/app/tests/suites/TestSubscribe_AdministratorCommissioning.yaml
new file mode 100644
index 0000000..ecda538
--- /dev/null
+++ b/src/app/tests/suites/TestSubscribe_AdministratorCommissioning.yaml
@@ -0,0 +1,135 @@
+# Copyright (c) 2021 Project CHIP Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+name: Subscribe Tests - Administrator Commissioning Cluster
+
+config:
+    nodeId: 0x12344321
+    cluster: "AdministratorCommissioning"
+    endpoint: 0
+    ourVendorId:
+        type: int16u
+        defaultValue: 0xFFF1
+
+tests:
+    - label: "Wait for the commissioned device to be retrieved"
+      cluster: "DelayCommands"
+      command: "WaitForCommissionee"
+      arguments:
+          values:
+              - name: "nodeId"
+                value: nodeId
+
+    - label: "Get ourfabric index"
+      cluster: "Operational Credentials"
+      command: "readAttribute"
+      attribute: "CurrentFabricIndex"
+      response:
+          saveAs: ourFabricIndex
+
+    - label: "Subscribe WindowStatus Attribute"
+      command: "subscribeAttribute"
+      attribute: "WindowStatus"
+      minInterval: 2
+      maxInterval: 50
+      response:
+          value: 0
+
+    - label: "Open the commissioning window 1"
+      command: "OpenBasicCommissioningWindow"
+      timedInteractionTimeoutMs: 10000
+      arguments:
+          values:
+              - name: "CommissioningTimeout"
+                value: 180
+
+    - label: "Check for first attribute report for WindowStatus"
+      command: "waitForReport"
+      attribute: "WindowStatus"
+      response:
+          value: 2
+
+    - label: "Close the commissioning window 1"
+      command: "RevokeCommissioning"
+      timedInteractionTimeoutMs: 10000
+
+    - label: "Check for second attribute report for WindowStatus"
+      command: "waitForReport"
+      attribute: "WindowStatus"
+      response:
+          value: 0
+
+    - label: "Subscribe AdminVendorId Attribute"
+      command: "subscribeAttribute"
+      attribute: "AdminVendorId"
+      minInterval: 2
+      maxInterval: 50
+      response:
+          value: null
+
+    - label: "Open the commissioning window 2"
+      command: "OpenBasicCommissioningWindow"
+      timedInteractionTimeoutMs: 10000
+      arguments:
+          values:
+              - name: "CommissioningTimeout"
+                value: 180
+
+    - label: "Check for first attribute report for AdminVendorId"
+      command: "waitForReport"
+      attribute: "AdminVendorId"
+      response:
+          value: ourVendorId
+
+    - label: "Close the commissioning window 2"
+      command: "RevokeCommissioning"
+      timedInteractionTimeoutMs: 10000
+
+    - label: "Check for second attribute report for AdminVendorId"
+      command: "waitForReport"
+      attribute: "AdminVendorId"
+      response:
+          value: null
+
+    - label: "Subscribe AdminFabricIndex Attribute"
+      command: "subscribeAttribute"
+      attribute: "AdminFabricIndex"
+      minInterval: 2
+      maxInterval: 50
+      response:
+          value: null
+
+    - label: "Open the commissioning window 3"
+      command: "OpenBasicCommissioningWindow"
+      timedInteractionTimeoutMs: 10000
+      arguments:
+          values:
+              - name: "CommissioningTimeout"
+                value: 180
+
+    - label: "Check for first attribute report for AdminFabricIndex"
+      command: "waitForReport"
+      attribute: "AdminFabricIndex"
+      response:
+          value: ourFabricIndex
+
+    - label: "Close the commissioning window 2"
+      command: "RevokeCommissioning"
+      timedInteractionTimeoutMs: 10000
+
+    - label: "Check for second attribute report for AdminFabricIndex"
+      command: "waitForReport"
+      attribute: "AdminFabricIndex"
+      response:
+          value: null
diff --git a/src/app/tests/suites/ciTests.json b/src/app/tests/suites/ciTests.json
index 17bfa98..58a3bd5 100644
--- a/src/app/tests/suites/ciTests.json
+++ b/src/app/tests/suites/ciTests.json
@@ -227,7 +227,10 @@
     ],
     "MultiAdmin": ["TestMultiAdmin"],
     "SoftwareDiagnostics": ["Test_TC_DGSW_1_1"],
-    "Subscriptions": ["TestSubscribe_OnOff"],
+    "Subscriptions": [
+        "TestSubscribe_OnOff",
+        "TestSubscribe_AdministratorCommissioning"
+    ],
     "DoorLock": [
         "DL_UsersAndCredentials",
         "DL_LockUnlock",
diff --git a/src/app/util/attribute-table.cpp b/src/app/util/attribute-table.cpp
index 2a86c16..3c05b68 100644
--- a/src/app/util/attribute-table.cpp
+++ b/src/app/util/attribute-table.cpp
@@ -359,7 +359,7 @@
         // The callee will weed out attributes that do not need to be stored.
         emAfSaveAttributeToStorageIfNeeded(data, endpoint, cluster, metadata);
 
-        MatterReportingAttributeChangeCallback(endpoint, cluster, attributeID, dataType, data);
+        MatterReportingAttributeChangeCallback(endpoint, cluster, attributeID);
 
         // Post write attribute callback for all attributes changes, regardless
         // of cluster.
diff --git a/src/app/util/ember-compatibility-functions.cpp b/src/app/util/ember-compatibility-functions.cpp
index 648e296..683da9c 100644
--- a/src/app/util/ember-compatibility-functions.cpp
+++ b/src/app/util/ember-compatibility-functions.cpp
@@ -1107,15 +1107,6 @@
 } // namespace app
 } // namespace chip
 
-void MatterReportingAttributeChangeCallback(EndpointId endpoint, ClusterId clusterId, AttributeId attributeId,
-                                            EmberAfAttributeType type, uint8_t * data)
-{
-    IgnoreUnusedVariable(type);
-    IgnoreUnusedVariable(data);
-
-    MatterReportingAttributeChangeCallback(endpoint, clusterId, attributeId);
-}
-
 void MatterReportingAttributeChangeCallback(EndpointId endpoint, ClusterId clusterId, AttributeId attributeId)
 {
     // Attribute writes have asserted this already, but this assert should catch
diff --git a/zzz_generated/chip-tool/zap-generated/test/Commands.h b/zzz_generated/chip-tool/zap-generated/test/Commands.h
index 1c8402f..d387909 100644
--- a/zzz_generated/chip-tool/zap-generated/test/Commands.h
+++ b/zzz_generated/chip-tool/zap-generated/test/Commands.h
@@ -235,6 +235,7 @@
         printf("TestMultiAdmin\n");
         printf("Test_TC_DGSW_1_1\n");
         printf("TestSubscribe_OnOff\n");
+        printf("TestSubscribe_AdministratorCommissioning\n");
         printf("DL_UsersAndCredentials\n");
         printf("DL_LockUnlock\n");
         printf("DL_Schedules\n");
@@ -63169,8 +63170,6 @@
         AddArgument("cluster", &mCluster);
         AddArgument("discriminator", 0, UINT16_MAX, &mDiscriminator);
         AddArgument("payload", &mPayload);
-        AddArgument("alphaIndex", 0, UINT8_MAX, &mAlphaIndex);
-        AddArgument("betaIndex", 0, UINT8_MAX, &mBetaIndex);
         AddArgument("timeout", 0, UINT16_MAX, &mTimeout);
     }
 
@@ -63188,10 +63187,10 @@
     chip::Optional<chip::CharSpan> mCluster;
     chip::Optional<uint16_t> mDiscriminator;
     chip::Optional<chip::CharSpan> mPayload;
-    chip::Optional<uint8_t> mAlphaIndex;
-    chip::Optional<uint8_t> mBetaIndex;
     chip::Optional<uint16_t> mTimeout;
 
+    uint8_t alphaIndex;
+    uint8_t betaIndex;
     chip::app::DataModel::Nullable<uint16_t> adminVendorId;
 
     chip::EndpointId GetEndpoint(chip::EndpointId endpoint) { return mEndpoint.HasValue() ? mEndpoint.Value() : endpoint; }
@@ -63215,7 +63214,7 @@
             {
                 uint8_t value;
                 VerifyOrReturn(CheckDecodeValue(chip::app::DataModel::Decode(*data, value)));
-                VerifyOrReturn(CheckValue("currentFabricIndex", value, mAlphaIndex.HasValue() ? mAlphaIndex.Value() : 1U));
+                alphaIndex = value;
             }
             break;
         case 2:
@@ -63259,8 +63258,7 @@
                 chip::app::DataModel::Nullable<chip::FabricIndex> value;
                 VerifyOrReturn(CheckDecodeValue(chip::app::DataModel::Decode(*data, value)));
                 VerifyOrReturn(CheckValueNonNull("adminFabricIndex", value));
-                VerifyOrReturn(
-                    CheckValue("adminFabricIndex.Value()", value.Value(), mAlphaIndex.HasValue() ? mAlphaIndex.Value() : 1U));
+                VerifyOrReturn(CheckValue("adminFabricIndex.Value()", value.Value(), alphaIndex));
             }
             break;
         case 8:
@@ -63338,7 +63336,7 @@
             {
                 uint8_t value;
                 VerifyOrReturn(CheckDecodeValue(chip::app::DataModel::Decode(*data, value)));
-                VerifyOrReturn(CheckValue("currentFabricIndex", value, mBetaIndex.HasValue() ? mBetaIndex.Value() : 2U));
+                betaIndex = value;
             }
             break;
         case 20:
@@ -63358,8 +63356,7 @@
                 chip::app::DataModel::Nullable<chip::FabricIndex> value;
                 VerifyOrReturn(CheckDecodeValue(chip::app::DataModel::Decode(*data, value)));
                 VerifyOrReturn(CheckValueNonNull("adminFabricIndex", value));
-                VerifyOrReturn(
-                    CheckValue("adminFabricIndex.Value()", value.Value(), mBetaIndex.HasValue() ? mBetaIndex.Value() : 2U));
+                VerifyOrReturn(CheckValue("adminFabricIndex.Value()", value.Value(), betaIndex));
             }
             break;
         case 23:
@@ -63579,7 +63576,7 @@
             LogStep(24, "Remove beta fabric");
             ListFreer listFreer;
             chip::app::Clusters::OperationalCredentials::Commands::RemoveFabric::Type value;
-            value.fabricIndex = mBetaIndex.HasValue() ? mBetaIndex.Value() : 2U;
+            value.fabricIndex = betaIndex;
             return SendCommand(kIdentityAlpha, GetEndpoint(0), OperationalCredentials::Id,
                                OperationalCredentials::Commands::RemoveFabric::Id, value, chip::NullOptional
 
@@ -64290,6 +64287,295 @@
     }
 };
 
+class TestSubscribe_AdministratorCommissioningSuite : public TestCommand
+{
+public:
+    TestSubscribe_AdministratorCommissioningSuite(CredentialIssuerCommands * credsIssuerConfig) :
+        TestCommand("TestSubscribe_AdministratorCommissioning", 17, credsIssuerConfig)
+    {
+        AddArgument("nodeId", 0, UINT64_MAX, &mNodeId);
+        AddArgument("cluster", &mCluster);
+        AddArgument("endpoint", 0, UINT16_MAX, &mEndpoint);
+        AddArgument("ourVendorId", 0, UINT16_MAX, &mOurVendorId);
+        AddArgument("timeout", 0, UINT16_MAX, &mTimeout);
+    }
+
+    ~TestSubscribe_AdministratorCommissioningSuite() {}
+
+    chip::System::Clock::Timeout GetWaitDuration() const override
+    {
+        return chip::System::Clock::Seconds16(mTimeout.ValueOr(kTimeoutInSeconds));
+    }
+
+private:
+    chip::Optional<chip::NodeId> mNodeId;
+    chip::Optional<chip::CharSpan> mCluster;
+    chip::Optional<chip::EndpointId> mEndpoint;
+    chip::Optional<uint16_t> mOurVendorId;
+    chip::Optional<uint16_t> mTimeout;
+
+    uint8_t ourFabricIndex;
+
+    chip::EndpointId GetEndpoint(chip::EndpointId endpoint) { return mEndpoint.HasValue() ? mEndpoint.Value() : endpoint; }
+
+    //
+    // Tests methods
+    //
+
+    void OnResponse(const chip::app::StatusIB & status, chip::TLV::TLVReader * data) override
+    {
+        bool shouldContinue = false;
+
+        switch (mTestIndex - 1)
+        {
+        case 0:
+            VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0));
+            shouldContinue = true;
+            break;
+        case 1:
+            VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0));
+            {
+                uint8_t value;
+                VerifyOrReturn(CheckDecodeValue(chip::app::DataModel::Decode(*data, value)));
+                ourFabricIndex = value;
+            }
+            break;
+        case 2:
+            VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0));
+            {
+                chip::app::Clusters::AdministratorCommissioning::CommissioningWindowStatus value;
+                VerifyOrReturn(CheckDecodeValue(chip::app::DataModel::Decode(*data, value)));
+                VerifyOrReturn(CheckValue("windowStatus", value, 0U));
+            }
+            break;
+        case 3:
+            VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0));
+            break;
+        case 4:
+            VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0));
+            {
+                chip::app::Clusters::AdministratorCommissioning::CommissioningWindowStatus value;
+                VerifyOrReturn(CheckDecodeValue(chip::app::DataModel::Decode(*data, value)));
+                VerifyOrReturn(CheckValue("windowStatus", value, 2U));
+            }
+            shouldContinue = true;
+            break;
+        case 5:
+            VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0));
+            break;
+        case 6:
+            VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0));
+            {
+                chip::app::Clusters::AdministratorCommissioning::CommissioningWindowStatus value;
+                VerifyOrReturn(CheckDecodeValue(chip::app::DataModel::Decode(*data, value)));
+                VerifyOrReturn(CheckValue("windowStatus", value, 0U));
+            }
+            shouldContinue = true;
+            break;
+        case 7:
+            VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0));
+            {
+                chip::app::DataModel::Nullable<uint16_t> value;
+                VerifyOrReturn(CheckDecodeValue(chip::app::DataModel::Decode(*data, value)));
+                VerifyOrReturn(CheckValueNull("adminVendorId", value));
+            }
+            break;
+        case 8:
+            VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0));
+            break;
+        case 9:
+            VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0));
+            {
+                chip::app::DataModel::Nullable<uint16_t> value;
+                VerifyOrReturn(CheckDecodeValue(chip::app::DataModel::Decode(*data, value)));
+                VerifyOrReturn(CheckValueNonNull("adminVendorId", value));
+                VerifyOrReturn(
+                    CheckValue("adminVendorId.Value()", value.Value(), mOurVendorId.HasValue() ? mOurVendorId.Value() : 65521U));
+            }
+            shouldContinue = true;
+            break;
+        case 10:
+            VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0));
+            break;
+        case 11:
+            VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0));
+            {
+                chip::app::DataModel::Nullable<uint16_t> value;
+                VerifyOrReturn(CheckDecodeValue(chip::app::DataModel::Decode(*data, value)));
+                VerifyOrReturn(CheckValueNull("adminVendorId", value));
+            }
+            shouldContinue = true;
+            break;
+        case 12:
+            VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0));
+            {
+                chip::app::DataModel::Nullable<chip::FabricIndex> value;
+                VerifyOrReturn(CheckDecodeValue(chip::app::DataModel::Decode(*data, value)));
+                VerifyOrReturn(CheckValueNull("adminFabricIndex", value));
+            }
+            break;
+        case 13:
+            VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0));
+            break;
+        case 14:
+            VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0));
+            {
+                chip::app::DataModel::Nullable<chip::FabricIndex> value;
+                VerifyOrReturn(CheckDecodeValue(chip::app::DataModel::Decode(*data, value)));
+                VerifyOrReturn(CheckValueNonNull("adminFabricIndex", value));
+                VerifyOrReturn(CheckValue("adminFabricIndex.Value()", value.Value(), ourFabricIndex));
+            }
+            shouldContinue = true;
+            break;
+        case 15:
+            VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0));
+            break;
+        case 16:
+            VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0));
+            {
+                chip::app::DataModel::Nullable<chip::FabricIndex> value;
+                VerifyOrReturn(CheckDecodeValue(chip::app::DataModel::Decode(*data, value)));
+                VerifyOrReturn(CheckValueNull("adminFabricIndex", value));
+            }
+            shouldContinue = true;
+            break;
+        default:
+            LogErrorOnFailure(ContinueOnChipMainThread(CHIP_ERROR_INVALID_ARGUMENT));
+        }
+
+        if (shouldContinue)
+        {
+            ContinueOnChipMainThread(CHIP_NO_ERROR);
+        }
+    }
+
+    CHIP_ERROR DoTestStep(uint16_t testIndex) override
+    {
+        using namespace chip::app::Clusters;
+        switch (testIndex)
+        {
+        case 0: {
+            LogStep(0, "Wait for the commissioned device to be retrieved");
+            ListFreer listFreer;
+            chip::app::Clusters::DelayCommands::Commands::WaitForCommissionee::Type value;
+            value.nodeId = mNodeId.HasValue() ? mNodeId.Value() : 305414945ULL;
+            return WaitForCommissionee(kIdentityAlpha, value);
+        }
+        case 1: {
+            LogStep(1, "Get ourfabric index");
+            return ReadAttribute(kIdentityAlpha, GetEndpoint(0), OperationalCredentials::Id,
+                                 OperationalCredentials::Attributes::CurrentFabricIndex::Id, true, chip::NullOptional);
+        }
+        case 2: {
+            LogStep(2, "Subscribe WindowStatus Attribute");
+            return SubscribeAttribute(kIdentityAlpha, GetEndpoint(0), AdministratorCommissioning::Id,
+                                      AdministratorCommissioning::Attributes::WindowStatus::Id, 2, 50, true, chip::NullOptional,
+                                      chip::NullOptional, /* autoResubscribe = */ chip::NullOptional);
+        }
+        case 3: {
+            LogStep(3, "Open the commissioning window 1");
+            ListFreer listFreer;
+            chip::app::Clusters::AdministratorCommissioning::Commands::OpenBasicCommissioningWindow::Type value;
+            value.commissioningTimeout = 180U;
+            return SendCommand(kIdentityAlpha, GetEndpoint(0), AdministratorCommissioning::Id,
+                               AdministratorCommissioning::Commands::OpenBasicCommissioningWindow::Id, value,
+                               chip::Optional<uint16_t>(10000), chip::NullOptional
+
+            );
+        }
+        case 4: {
+            LogStep(4, "Check for first attribute report for WindowStatus");
+            return WaitForReport();
+        }
+        case 5: {
+            LogStep(5, "Close the commissioning window 1");
+            ListFreer listFreer;
+            chip::app::Clusters::AdministratorCommissioning::Commands::RevokeCommissioning::Type value;
+            return SendCommand(kIdentityAlpha, GetEndpoint(0), AdministratorCommissioning::Id,
+                               AdministratorCommissioning::Commands::RevokeCommissioning::Id, value,
+                               chip::Optional<uint16_t>(10000), chip::NullOptional
+
+            );
+        }
+        case 6: {
+            LogStep(6, "Check for second attribute report for WindowStatus");
+            return WaitForReport();
+        }
+        case 7: {
+            LogStep(7, "Subscribe AdminVendorId Attribute");
+            return SubscribeAttribute(kIdentityAlpha, GetEndpoint(0), AdministratorCommissioning::Id,
+                                      AdministratorCommissioning::Attributes::AdminVendorId::Id, 2, 50, true, chip::NullOptional,
+                                      chip::NullOptional, /* autoResubscribe = */ chip::NullOptional);
+        }
+        case 8: {
+            LogStep(8, "Open the commissioning window 2");
+            ListFreer listFreer;
+            chip::app::Clusters::AdministratorCommissioning::Commands::OpenBasicCommissioningWindow::Type value;
+            value.commissioningTimeout = 180U;
+            return SendCommand(kIdentityAlpha, GetEndpoint(0), AdministratorCommissioning::Id,
+                               AdministratorCommissioning::Commands::OpenBasicCommissioningWindow::Id, value,
+                               chip::Optional<uint16_t>(10000), chip::NullOptional
+
+            );
+        }
+        case 9: {
+            LogStep(9, "Check for first attribute report for AdminVendorId");
+            return WaitForReport();
+        }
+        case 10: {
+            LogStep(10, "Close the commissioning window 2");
+            ListFreer listFreer;
+            chip::app::Clusters::AdministratorCommissioning::Commands::RevokeCommissioning::Type value;
+            return SendCommand(kIdentityAlpha, GetEndpoint(0), AdministratorCommissioning::Id,
+                               AdministratorCommissioning::Commands::RevokeCommissioning::Id, value,
+                               chip::Optional<uint16_t>(10000), chip::NullOptional
+
+            );
+        }
+        case 11: {
+            LogStep(11, "Check for second attribute report for AdminVendorId");
+            return WaitForReport();
+        }
+        case 12: {
+            LogStep(12, "Subscribe AdminFabricIndex Attribute");
+            return SubscribeAttribute(kIdentityAlpha, GetEndpoint(0), AdministratorCommissioning::Id,
+                                      AdministratorCommissioning::Attributes::AdminFabricIndex::Id, 2, 50, true, chip::NullOptional,
+                                      chip::NullOptional, /* autoResubscribe = */ chip::NullOptional);
+        }
+        case 13: {
+            LogStep(13, "Open the commissioning window 3");
+            ListFreer listFreer;
+            chip::app::Clusters::AdministratorCommissioning::Commands::OpenBasicCommissioningWindow::Type value;
+            value.commissioningTimeout = 180U;
+            return SendCommand(kIdentityAlpha, GetEndpoint(0), AdministratorCommissioning::Id,
+                               AdministratorCommissioning::Commands::OpenBasicCommissioningWindow::Id, value,
+                               chip::Optional<uint16_t>(10000), chip::NullOptional
+
+            );
+        }
+        case 14: {
+            LogStep(14, "Check for first attribute report for AdminFabricIndex");
+            return WaitForReport();
+        }
+        case 15: {
+            LogStep(15, "Close the commissioning window 2");
+            ListFreer listFreer;
+            chip::app::Clusters::AdministratorCommissioning::Commands::RevokeCommissioning::Type value;
+            return SendCommand(kIdentityAlpha, GetEndpoint(0), AdministratorCommissioning::Id,
+                               AdministratorCommissioning::Commands::RevokeCommissioning::Id, value,
+                               chip::Optional<uint16_t>(10000), chip::NullOptional
+
+            );
+        }
+        case 16: {
+            LogStep(16, "Check for second attribute report for AdminFabricIndex");
+            return WaitForReport();
+        }
+        }
+        return CHIP_NO_ERROR;
+    }
+};
+
 class DL_UsersAndCredentialsSuite : public TestCommand
 {
 public:
@@ -104645,6 +104931,7 @@
         make_unique<TestMultiAdminSuite>(credsIssuerConfig),
         make_unique<Test_TC_DGSW_1_1Suite>(credsIssuerConfig),
         make_unique<TestSubscribe_OnOffSuite>(credsIssuerConfig),
+        make_unique<TestSubscribe_AdministratorCommissioningSuite>(credsIssuerConfig),
         make_unique<DL_UsersAndCredentialsSuite>(credsIssuerConfig),
         make_unique<DL_LockUnlockSuite>(credsIssuerConfig),
         make_unique<DL_SchedulesSuite>(credsIssuerConfig),
diff --git a/zzz_generated/darwin-framework-tool/zap-generated/test/Commands.h b/zzz_generated/darwin-framework-tool/zap-generated/test/Commands.h
index 0c4c3e8..3fb1a5c 100644
--- a/zzz_generated/darwin-framework-tool/zap-generated/test/Commands.h
+++ b/zzz_generated/darwin-framework-tool/zap-generated/test/Commands.h
@@ -216,6 +216,7 @@
         printf("TestMultiAdmin\n");
         printf("Test_TC_DGSW_1_1\n");
         printf("TestSubscribe_OnOff\n");
+        printf("TestSubscribe_AdministratorCommissioning\n");
         printf("DL_UsersAndCredentials\n");
         printf("DL_LockUnlock\n");
         printf("DL_Schedules\n");
@@ -100150,8 +100151,6 @@
         AddArgument("cluster", &mCluster);
         AddArgument("discriminator", 0, UINT16_MAX, &mDiscriminator);
         AddArgument("payload", &mPayload);
-        AddArgument("alphaIndex", 0, UINT8_MAX, &mAlphaIndex);
-        AddArgument("betaIndex", 0, UINT8_MAX, &mBetaIndex);
         AddArgument("timeout", 0, UINT16_MAX, &mTimeout);
     }
     // NOLINTEND(clang-analyzer-nullability.NullPassedToNonnull)
@@ -100408,8 +100407,6 @@
     chip::Optional<chip::CharSpan> mCluster;
     chip::Optional<uint16_t> mDiscriminator;
     chip::Optional<chip::CharSpan> mPayload;
-    chip::Optional<uint8_t> mAlphaIndex;
-    chip::Optional<uint8_t> mBetaIndex;
     chip::Optional<uint16_t> mTimeout;
 
     CHIP_ERROR TestWaitForTheCommissionedDeviceToBeRetrievedForAlpha_0()
@@ -100418,6 +100415,7 @@
         value.nodeId = mNodeId.HasValue() ? mNodeId.Value() : 305414945ULL;
         return WaitForCommissionee("alpha", value);
     }
+    NSNumber * _Nonnull alphaIndex;
 
     CHIP_ERROR TestGetAlphasFabricIndex_1()
     {
@@ -100432,8 +100430,7 @@
             VerifyOrReturn(CheckValue("status", err ? err.code : 0, 0));
 
             {
-                id actualValue = value;
-                VerifyOrReturn(CheckValue("CurrentFabricIndex", actualValue, mAlphaIndex.HasValue() ? mAlphaIndex.Value() : 1U));
+                alphaIndex = value;
             }
 
             NextTest();
@@ -100569,8 +100566,12 @@
 
             {
                 id actualValue = value;
-                VerifyOrReturn(CheckValueNonNull("AdminFabricIndex", actualValue));
-                VerifyOrReturn(CheckValue("AdminFabricIndex", actualValue, mAlphaIndex.HasValue() ? mAlphaIndex.Value() : 1U));
+                if (alphaIndex == nil) {
+                    VerifyOrReturn(CheckValueNull("AdminFabricIndex", actualValue));
+                } else {
+                    VerifyOrReturn(CheckValueNonNull("AdminFabricIndex", actualValue));
+                    VerifyOrReturn(CheckValue("AdminFabricIndex", actualValue, alphaIndex));
+                }
             }
 
             NextTest();
@@ -100792,6 +100793,7 @@
 
         return CHIP_NO_ERROR;
     }
+    NSNumber * _Nonnull betaIndex;
 
     CHIP_ERROR TestGetBetasFabricIndex_19()
     {
@@ -100806,8 +100808,7 @@
             VerifyOrReturn(CheckValue("status", err ? err.code : 0, 0));
 
             {
-                id actualValue = value;
-                VerifyOrReturn(CheckValue("CurrentFabricIndex", actualValue, mBetaIndex.HasValue() ? mBetaIndex.Value() : 2U));
+                betaIndex = value;
             }
 
             NextTest();
@@ -100874,8 +100875,12 @@
 
             {
                 id actualValue = value;
-                VerifyOrReturn(CheckValueNonNull("AdminFabricIndex", actualValue));
-                VerifyOrReturn(CheckValue("AdminFabricIndex", actualValue, mBetaIndex.HasValue() ? mBetaIndex.Value() : 2U));
+                if (betaIndex == nil) {
+                    VerifyOrReturn(CheckValueNull("AdminFabricIndex", actualValue));
+                } else {
+                    VerifyOrReturn(CheckValueNonNull("AdminFabricIndex", actualValue));
+                    VerifyOrReturn(CheckValue("AdminFabricIndex", actualValue, betaIndex));
+                }
             }
 
             NextTest();
@@ -100918,8 +100923,7 @@
         VerifyOrReturnError(cluster != nil, CHIP_ERROR_INCORRECT_STATE);
 
         __auto_type * params = [[MTROperationalCredentialsClusterRemoveFabricParams alloc] init];
-        params.fabricIndex
-            = mBetaIndex.HasValue() ? [NSNumber numberWithUnsignedChar:mBetaIndex.Value()] : [NSNumber numberWithUnsignedChar:2U];
+        params.fabricIndex = [betaIndex copy];
         [cluster removeFabricWithParams:params
                              completion:^(
                                  MTROperationalCredentialsClusterNOCResponseParams * _Nullable values, NSError * _Nullable err) {
@@ -102208,6 +102212,695 @@
     }
 };
 
+class TestSubscribe_AdministratorCommissioning : public TestCommandBridge {
+public:
+    // NOLINTBEGIN(clang-analyzer-nullability.NullPassedToNonnull): Test constructor nullability not enforced
+    TestSubscribe_AdministratorCommissioning()
+        : TestCommandBridge("TestSubscribe_AdministratorCommissioning")
+        , mTestIndex(0)
+    {
+        AddArgument("nodeId", 0, UINT64_MAX, &mNodeId);
+        AddArgument("cluster", &mCluster);
+        AddArgument("endpoint", 0, UINT16_MAX, &mEndpoint);
+        AddArgument("ourVendorId", 0, UINT16_MAX, &mOurVendorId);
+        AddArgument("timeout", 0, UINT16_MAX, &mTimeout);
+    }
+    // NOLINTEND(clang-analyzer-nullability.NullPassedToNonnull)
+
+    ~TestSubscribe_AdministratorCommissioning() {}
+
+    /////////// TestCommand Interface /////////
+    void NextTest() override
+    {
+        CHIP_ERROR err = CHIP_NO_ERROR;
+
+        if (0 == mTestIndex) {
+            ChipLogProgress(chipTool, " **** Test Start: TestSubscribe_AdministratorCommissioning\n");
+        }
+
+        if (mTestCount == mTestIndex) {
+            ChipLogProgress(chipTool, " **** Test Complete: TestSubscribe_AdministratorCommissioning\n");
+            SetCommandExitStatus(CHIP_NO_ERROR);
+            return;
+        }
+
+        Wait();
+
+        // Ensure we increment mTestIndex before we start running the relevant
+        // command.  That way if we lose the timeslice after we send the message
+        // but before our function call returns, we won't end up with an
+        // incorrect mTestIndex value observed when we get the response.
+        switch (mTestIndex++) {
+        case 0:
+            ChipLogProgress(chipTool, " ***** Test Step 0 : Wait for the commissioned device to be retrieved\n");
+            err = TestWaitForTheCommissionedDeviceToBeRetrieved_0();
+            break;
+        case 1:
+            ChipLogProgress(chipTool, " ***** Test Step 1 : Get ourfabric index\n");
+            err = TestGetOurfabricIndex_1();
+            break;
+        case 2:
+            ChipLogProgress(chipTool, " ***** Test Step 2 : Report: Subscribe WindowStatus Attribute\n");
+            err = TestReportSubscribeWindowStatusAttribute_2();
+            break;
+        case 3:
+            ChipLogProgress(chipTool, " ***** Test Step 3 : Subscribe WindowStatus Attribute\n");
+            err = TestSubscribeWindowStatusAttribute_3();
+            break;
+        case 4:
+            ChipLogProgress(chipTool, " ***** Test Step 4 : Open the commissioning window 1\n");
+            err = TestOpenTheCommissioningWindow1_4();
+            break;
+        case 5:
+            ChipLogProgress(chipTool, " ***** Test Step 5 : Check for first attribute report for WindowStatus\n");
+            err = TestCheckForFirstAttributeReportForWindowStatus_5();
+            break;
+        case 6:
+            ChipLogProgress(chipTool, " ***** Test Step 6 : Close the commissioning window 1\n");
+            err = TestCloseTheCommissioningWindow1_6();
+            break;
+        case 7:
+            ChipLogProgress(chipTool, " ***** Test Step 7 : Check for second attribute report for WindowStatus\n");
+            err = TestCheckForSecondAttributeReportForWindowStatus_7();
+            break;
+        case 8:
+            ChipLogProgress(chipTool, " ***** Test Step 8 : Report: Subscribe AdminVendorId Attribute\n");
+            err = TestReportSubscribeAdminVendorIdAttribute_8();
+            break;
+        case 9:
+            ChipLogProgress(chipTool, " ***** Test Step 9 : Subscribe AdminVendorId Attribute\n");
+            err = TestSubscribeAdminVendorIdAttribute_9();
+            break;
+        case 10:
+            ChipLogProgress(chipTool, " ***** Test Step 10 : Open the commissioning window 2\n");
+            err = TestOpenTheCommissioningWindow2_10();
+            break;
+        case 11:
+            ChipLogProgress(chipTool, " ***** Test Step 11 : Check for first attribute report for AdminVendorId\n");
+            err = TestCheckForFirstAttributeReportForAdminVendorId_11();
+            break;
+        case 12:
+            ChipLogProgress(chipTool, " ***** Test Step 12 : Close the commissioning window 2\n");
+            err = TestCloseTheCommissioningWindow2_12();
+            break;
+        case 13:
+            ChipLogProgress(chipTool, " ***** Test Step 13 : Check for second attribute report for AdminVendorId\n");
+            err = TestCheckForSecondAttributeReportForAdminVendorId_13();
+            break;
+        case 14:
+            ChipLogProgress(chipTool, " ***** Test Step 14 : Report: Subscribe AdminFabricIndex Attribute\n");
+            err = TestReportSubscribeAdminFabricIndexAttribute_14();
+            break;
+        case 15:
+            ChipLogProgress(chipTool, " ***** Test Step 15 : Subscribe AdminFabricIndex Attribute\n");
+            err = TestSubscribeAdminFabricIndexAttribute_15();
+            break;
+        case 16:
+            ChipLogProgress(chipTool, " ***** Test Step 16 : Open the commissioning window 3\n");
+            err = TestOpenTheCommissioningWindow3_16();
+            break;
+        case 17:
+            ChipLogProgress(chipTool, " ***** Test Step 17 : Check for first attribute report for AdminFabricIndex\n");
+            err = TestCheckForFirstAttributeReportForAdminFabricIndex_17();
+            break;
+        case 18:
+            ChipLogProgress(chipTool, " ***** Test Step 18 : Close the commissioning window 2\n");
+            err = TestCloseTheCommissioningWindow2_18();
+            break;
+        case 19:
+            ChipLogProgress(chipTool, " ***** Test Step 19 : Check for second attribute report for AdminFabricIndex\n");
+            err = TestCheckForSecondAttributeReportForAdminFabricIndex_19();
+            break;
+        }
+
+        if (CHIP_NO_ERROR != err) {
+            ChipLogError(chipTool, " ***** Test Failure: %s\n", chip::ErrorStr(err));
+            SetCommandExitStatus(err);
+        }
+    }
+
+    void OnStatusUpdate(const chip::app::StatusIB & status) override
+    {
+        switch (mTestIndex - 1) {
+        case 0:
+            VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0));
+            break;
+        case 1:
+            VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0));
+            break;
+        case 2:
+            VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0));
+            break;
+        case 3:
+            VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0));
+            break;
+        case 4:
+            VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0));
+            break;
+        case 5:
+            VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0));
+            break;
+        case 6:
+            VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0));
+            break;
+        case 7:
+            VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0));
+            break;
+        case 8:
+            VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0));
+            break;
+        case 9:
+            VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0));
+            break;
+        case 10:
+            VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0));
+            break;
+        case 11:
+            VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0));
+            break;
+        case 12:
+            VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0));
+            break;
+        case 13:
+            VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0));
+            break;
+        case 14:
+            VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0));
+            break;
+        case 15:
+            VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0));
+            break;
+        case 16:
+            VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0));
+            break;
+        case 17:
+            VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0));
+            break;
+        case 18:
+            VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0));
+            break;
+        case 19:
+            VerifyOrReturn(CheckValue("status", chip::to_underlying(status.mStatus), 0));
+            break;
+        }
+
+        // Go on to the next test.
+        ContinueOnChipMainThread(CHIP_NO_ERROR);
+    }
+
+    chip::System::Clock::Timeout GetWaitDuration() const override
+    {
+        return chip::System::Clock::Seconds16(mTimeout.ValueOr(kTimeoutInSeconds));
+    }
+
+private:
+    std::atomic_uint16_t mTestIndex;
+    const uint16_t mTestCount = 20;
+
+    chip::Optional<chip::NodeId> mNodeId;
+    chip::Optional<chip::CharSpan> mCluster;
+    chip::Optional<chip::EndpointId> mEndpoint;
+    chip::Optional<uint16_t> mOurVendorId;
+    chip::Optional<uint16_t> mTimeout;
+
+    CHIP_ERROR TestWaitForTheCommissionedDeviceToBeRetrieved_0()
+    {
+        chip::app::Clusters::DelayCommands::Commands::WaitForCommissionee::Type value;
+        value.nodeId = mNodeId.HasValue() ? mNodeId.Value() : 305414945ULL;
+        return WaitForCommissionee("alpha", value);
+    }
+    NSNumber * _Nonnull ourFabricIndex;
+
+    CHIP_ERROR TestGetOurfabricIndex_1()
+    {
+        MTRBaseDevice * device = GetDevice("alpha");
+        MTRBaseClusterOperationalCredentials * cluster =
+            [[MTRBaseClusterOperationalCredentials alloc] initWithDevice:device endpointID:@(0) queue:mCallbackQueue];
+        VerifyOrReturnError(cluster != nil, CHIP_ERROR_INCORRECT_STATE);
+
+        [cluster readAttributeCurrentFabricIndexWithCompletion:^(NSNumber * _Nullable value, NSError * _Nullable err) {
+            NSLog(@"Get ourfabric index Error: %@", err);
+
+            VerifyOrReturn(CheckValue("status", err ? err.code : 0, 0));
+
+            {
+                ourFabricIndex = value;
+            }
+
+            NextTest();
+        }];
+
+        return CHIP_NO_ERROR;
+    }
+    bool testSendClusterTestSubscribe_AdministratorCommissioning_2_WaitForReport_Fulfilled = false;
+    ResponseHandler _Nullable test_TestSubscribe_AdministratorCommissioning_WindowStatus_Reported = nil;
+
+    CHIP_ERROR TestReportSubscribeWindowStatusAttribute_2()
+    {
+        MTRBaseDevice * device = GetDevice("alpha");
+        MTRBaseClusterAdministratorCommissioning * cluster =
+            [[MTRBaseClusterAdministratorCommissioning alloc] initWithDevice:device endpointID:@(0) queue:mCallbackQueue];
+        VerifyOrReturnError(cluster != nil, CHIP_ERROR_INCORRECT_STATE);
+
+        test_TestSubscribe_AdministratorCommissioning_WindowStatus_Reported
+            = ^(NSNumber * _Nullable value, NSError * _Nullable err) {
+                  NSLog(@"Report: Subscribe WindowStatus Attribute Error: %@", err);
+
+                  VerifyOrReturn(CheckValue("status", err ? err.code : 0, 0));
+
+                  {
+                      id actualValue = value;
+                      VerifyOrReturn(CheckValue("WindowStatus", actualValue, 0U));
+                  }
+
+                  testSendClusterTestSubscribe_AdministratorCommissioning_2_WaitForReport_Fulfilled = true;
+              };
+
+        NextTest();
+        return CHIP_NO_ERROR;
+    }
+
+    CHIP_ERROR TestSubscribeWindowStatusAttribute_3()
+    {
+        MTRBaseDevice * device = GetDevice("alpha");
+        MTRBaseClusterAdministratorCommissioning * cluster =
+            [[MTRBaseClusterAdministratorCommissioning alloc] initWithDevice:device endpointID:@(0) queue:mCallbackQueue];
+        VerifyOrReturnError(cluster != nil, CHIP_ERROR_INCORRECT_STATE);
+
+        uint16_t minIntervalArgument = 2U;
+        uint16_t maxIntervalArgument = 50U;
+        MTRSubscribeParams * params = [[MTRSubscribeParams alloc] initWithMinInterval:@(minIntervalArgument)
+                                                                          maxInterval:@(maxIntervalArgument)];
+        params.filterByFabric = true;
+        params.replaceExistingSubscriptions = true;
+        [cluster subscribeAttributeWindowStatusWithParams:params
+            subscriptionEstablished:^{
+                VerifyOrReturn(testSendClusterTestSubscribe_AdministratorCommissioning_2_WaitForReport_Fulfilled,
+                    SetCommandExitStatus(CHIP_ERROR_INCORRECT_STATE));
+                NextTest();
+            }
+            reportHandler:^(NSNumber * _Nullable value, NSError * _Nullable err) {
+                NSLog(@"Subscribe WindowStatus Attribute Error: %@", err);
+
+                VerifyOrReturn(CheckValue("status", err ? err.code : 0, 0));
+                if (test_TestSubscribe_AdministratorCommissioning_WindowStatus_Reported != nil) {
+                    ResponseHandler callback = test_TestSubscribe_AdministratorCommissioning_WindowStatus_Reported;
+                    test_TestSubscribe_AdministratorCommissioning_WindowStatus_Reported = nil;
+                    callback(value, err);
+                }
+            }];
+
+        return CHIP_NO_ERROR;
+    }
+
+    CHIP_ERROR TestOpenTheCommissioningWindow1_4()
+    {
+        MTRBaseDevice * device = GetDevice("alpha");
+        MTRBaseClusterAdministratorCommissioning * cluster =
+            [[MTRBaseClusterAdministratorCommissioning alloc] initWithDevice:device endpointID:@(0) queue:mCallbackQueue];
+        VerifyOrReturnError(cluster != nil, CHIP_ERROR_INCORRECT_STATE);
+
+        __auto_type * params = [[MTRAdministratorCommissioningClusterOpenBasicCommissioningWindowParams alloc] init];
+        params.commissioningTimeout = [NSNumber numberWithUnsignedShort:180U];
+        [cluster openBasicCommissioningWindowWithParams:params
+                                             completion:^(NSError * _Nullable err) {
+                                                 NSLog(@"Open the commissioning window 1 Error: %@", err);
+
+                                                 VerifyOrReturn(CheckValue("status", err ? err.code : 0, 0));
+
+                                                 NextTest();
+                                             }];
+
+        return CHIP_NO_ERROR;
+    }
+
+    CHIP_ERROR TestCheckForFirstAttributeReportForWindowStatus_5()
+    {
+        MTRBaseDevice * device = GetDevice("alpha");
+        MTRBaseClusterAdministratorCommissioning * cluster =
+            [[MTRBaseClusterAdministratorCommissioning alloc] initWithDevice:device endpointID:@(0) queue:mCallbackQueue];
+        VerifyOrReturnError(cluster != nil, CHIP_ERROR_INCORRECT_STATE);
+
+        test_TestSubscribe_AdministratorCommissioning_WindowStatus_Reported
+            = ^(NSNumber * _Nullable value, NSError * _Nullable err) {
+                  NSLog(@"Check for first attribute report for WindowStatus Error: %@", err);
+
+                  VerifyOrReturn(CheckValue("status", err ? err.code : 0, 0));
+
+                  {
+                      id actualValue = value;
+                      VerifyOrReturn(CheckValue("WindowStatus", actualValue, 2U));
+                  }
+
+                  NextTest();
+              };
+
+        return CHIP_NO_ERROR;
+    }
+
+    CHIP_ERROR TestCloseTheCommissioningWindow1_6()
+    {
+        MTRBaseDevice * device = GetDevice("alpha");
+        MTRBaseClusterAdministratorCommissioning * cluster =
+            [[MTRBaseClusterAdministratorCommissioning alloc] initWithDevice:device endpointID:@(0) queue:mCallbackQueue];
+        VerifyOrReturnError(cluster != nil, CHIP_ERROR_INCORRECT_STATE);
+
+        [cluster revokeCommissioningWithCompletion:^(NSError * _Nullable err) {
+            NSLog(@"Close the commissioning window 1 Error: %@", err);
+
+            VerifyOrReturn(CheckValue("status", err ? err.code : 0, 0));
+
+            NextTest();
+        }];
+
+        return CHIP_NO_ERROR;
+    }
+
+    CHIP_ERROR TestCheckForSecondAttributeReportForWindowStatus_7()
+    {
+        MTRBaseDevice * device = GetDevice("alpha");
+        MTRBaseClusterAdministratorCommissioning * cluster =
+            [[MTRBaseClusterAdministratorCommissioning alloc] initWithDevice:device endpointID:@(0) queue:mCallbackQueue];
+        VerifyOrReturnError(cluster != nil, CHIP_ERROR_INCORRECT_STATE);
+
+        test_TestSubscribe_AdministratorCommissioning_WindowStatus_Reported
+            = ^(NSNumber * _Nullable value, NSError * _Nullable err) {
+                  NSLog(@"Check for second attribute report for WindowStatus Error: %@", err);
+
+                  VerifyOrReturn(CheckValue("status", err ? err.code : 0, 0));
+
+                  {
+                      id actualValue = value;
+                      VerifyOrReturn(CheckValue("WindowStatus", actualValue, 0U));
+                  }
+
+                  NextTest();
+              };
+
+        return CHIP_NO_ERROR;
+    }
+    bool testSendClusterTestSubscribe_AdministratorCommissioning_8_WaitForReport_Fulfilled = false;
+    ResponseHandler _Nullable test_TestSubscribe_AdministratorCommissioning_AdminVendorId_Reported = nil;
+
+    CHIP_ERROR TestReportSubscribeAdminVendorIdAttribute_8()
+    {
+        MTRBaseDevice * device = GetDevice("alpha");
+        MTRBaseClusterAdministratorCommissioning * cluster =
+            [[MTRBaseClusterAdministratorCommissioning alloc] initWithDevice:device endpointID:@(0) queue:mCallbackQueue];
+        VerifyOrReturnError(cluster != nil, CHIP_ERROR_INCORRECT_STATE);
+
+        test_TestSubscribe_AdministratorCommissioning_AdminVendorId_Reported
+            = ^(NSNumber * _Nullable value, NSError * _Nullable err) {
+                  NSLog(@"Report: Subscribe AdminVendorId Attribute Error: %@", err);
+
+                  VerifyOrReturn(CheckValue("status", err ? err.code : 0, 0));
+
+                  {
+                      id actualValue = value;
+                      VerifyOrReturn(CheckValueNull("AdminVendorId", actualValue));
+                  }
+
+                  testSendClusterTestSubscribe_AdministratorCommissioning_8_WaitForReport_Fulfilled = true;
+              };
+
+        NextTest();
+        return CHIP_NO_ERROR;
+    }
+
+    CHIP_ERROR TestSubscribeAdminVendorIdAttribute_9()
+    {
+        MTRBaseDevice * device = GetDevice("alpha");
+        MTRBaseClusterAdministratorCommissioning * cluster =
+            [[MTRBaseClusterAdministratorCommissioning alloc] initWithDevice:device endpointID:@(0) queue:mCallbackQueue];
+        VerifyOrReturnError(cluster != nil, CHIP_ERROR_INCORRECT_STATE);
+
+        uint16_t minIntervalArgument = 2U;
+        uint16_t maxIntervalArgument = 50U;
+        MTRSubscribeParams * params = [[MTRSubscribeParams alloc] initWithMinInterval:@(minIntervalArgument)
+                                                                          maxInterval:@(maxIntervalArgument)];
+        params.filterByFabric = true;
+        params.replaceExistingSubscriptions = true;
+        [cluster subscribeAttributeAdminVendorIdWithParams:params
+            subscriptionEstablished:^{
+                VerifyOrReturn(testSendClusterTestSubscribe_AdministratorCommissioning_8_WaitForReport_Fulfilled,
+                    SetCommandExitStatus(CHIP_ERROR_INCORRECT_STATE));
+                NextTest();
+            }
+            reportHandler:^(NSNumber * _Nullable value, NSError * _Nullable err) {
+                NSLog(@"Subscribe AdminVendorId Attribute Error: %@", err);
+
+                VerifyOrReturn(CheckValue("status", err ? err.code : 0, 0));
+                if (test_TestSubscribe_AdministratorCommissioning_AdminVendorId_Reported != nil) {
+                    ResponseHandler callback = test_TestSubscribe_AdministratorCommissioning_AdminVendorId_Reported;
+                    test_TestSubscribe_AdministratorCommissioning_AdminVendorId_Reported = nil;
+                    callback(value, err);
+                }
+            }];
+
+        return CHIP_NO_ERROR;
+    }
+
+    CHIP_ERROR TestOpenTheCommissioningWindow2_10()
+    {
+        MTRBaseDevice * device = GetDevice("alpha");
+        MTRBaseClusterAdministratorCommissioning * cluster =
+            [[MTRBaseClusterAdministratorCommissioning alloc] initWithDevice:device endpointID:@(0) queue:mCallbackQueue];
+        VerifyOrReturnError(cluster != nil, CHIP_ERROR_INCORRECT_STATE);
+
+        __auto_type * params = [[MTRAdministratorCommissioningClusterOpenBasicCommissioningWindowParams alloc] init];
+        params.commissioningTimeout = [NSNumber numberWithUnsignedShort:180U];
+        [cluster openBasicCommissioningWindowWithParams:params
+                                             completion:^(NSError * _Nullable err) {
+                                                 NSLog(@"Open the commissioning window 2 Error: %@", err);
+
+                                                 VerifyOrReturn(CheckValue("status", err ? err.code : 0, 0));
+
+                                                 NextTest();
+                                             }];
+
+        return CHIP_NO_ERROR;
+    }
+
+    CHIP_ERROR TestCheckForFirstAttributeReportForAdminVendorId_11()
+    {
+        MTRBaseDevice * device = GetDevice("alpha");
+        MTRBaseClusterAdministratorCommissioning * cluster =
+            [[MTRBaseClusterAdministratorCommissioning alloc] initWithDevice:device endpointID:@(0) queue:mCallbackQueue];
+        VerifyOrReturnError(cluster != nil, CHIP_ERROR_INCORRECT_STATE);
+
+        test_TestSubscribe_AdministratorCommissioning_AdminVendorId_Reported = ^(
+            NSNumber * _Nullable value, NSError * _Nullable err) {
+            NSLog(@"Check for first attribute report for AdminVendorId Error: %@", err);
+
+            VerifyOrReturn(CheckValue("status", err ? err.code : 0, 0));
+
+            {
+                id actualValue = value;
+                VerifyOrReturn(CheckValueNonNull("AdminVendorId", actualValue));
+                VerifyOrReturn(CheckValue("AdminVendorId", actualValue, mOurVendorId.HasValue() ? mOurVendorId.Value() : 65521U));
+            }
+
+            NextTest();
+        };
+
+        return CHIP_NO_ERROR;
+    }
+
+    CHIP_ERROR TestCloseTheCommissioningWindow2_12()
+    {
+        MTRBaseDevice * device = GetDevice("alpha");
+        MTRBaseClusterAdministratorCommissioning * cluster =
+            [[MTRBaseClusterAdministratorCommissioning alloc] initWithDevice:device endpointID:@(0) queue:mCallbackQueue];
+        VerifyOrReturnError(cluster != nil, CHIP_ERROR_INCORRECT_STATE);
+
+        [cluster revokeCommissioningWithCompletion:^(NSError * _Nullable err) {
+            NSLog(@"Close the commissioning window 2 Error: %@", err);
+
+            VerifyOrReturn(CheckValue("status", err ? err.code : 0, 0));
+
+            NextTest();
+        }];
+
+        return CHIP_NO_ERROR;
+    }
+
+    CHIP_ERROR TestCheckForSecondAttributeReportForAdminVendorId_13()
+    {
+        MTRBaseDevice * device = GetDevice("alpha");
+        MTRBaseClusterAdministratorCommissioning * cluster =
+            [[MTRBaseClusterAdministratorCommissioning alloc] initWithDevice:device endpointID:@(0) queue:mCallbackQueue];
+        VerifyOrReturnError(cluster != nil, CHIP_ERROR_INCORRECT_STATE);
+
+        test_TestSubscribe_AdministratorCommissioning_AdminVendorId_Reported
+            = ^(NSNumber * _Nullable value, NSError * _Nullable err) {
+                  NSLog(@"Check for second attribute report for AdminVendorId Error: %@", err);
+
+                  VerifyOrReturn(CheckValue("status", err ? err.code : 0, 0));
+
+                  {
+                      id actualValue = value;
+                      VerifyOrReturn(CheckValueNull("AdminVendorId", actualValue));
+                  }
+
+                  NextTest();
+              };
+
+        return CHIP_NO_ERROR;
+    }
+    bool testSendClusterTestSubscribe_AdministratorCommissioning_14_WaitForReport_Fulfilled = false;
+    ResponseHandler _Nullable test_TestSubscribe_AdministratorCommissioning_AdminFabricIndex_Reported = nil;
+
+    CHIP_ERROR TestReportSubscribeAdminFabricIndexAttribute_14()
+    {
+        MTRBaseDevice * device = GetDevice("alpha");
+        MTRBaseClusterAdministratorCommissioning * cluster =
+            [[MTRBaseClusterAdministratorCommissioning alloc] initWithDevice:device endpointID:@(0) queue:mCallbackQueue];
+        VerifyOrReturnError(cluster != nil, CHIP_ERROR_INCORRECT_STATE);
+
+        test_TestSubscribe_AdministratorCommissioning_AdminFabricIndex_Reported
+            = ^(NSNumber * _Nullable value, NSError * _Nullable err) {
+                  NSLog(@"Report: Subscribe AdminFabricIndex Attribute Error: %@", err);
+
+                  VerifyOrReturn(CheckValue("status", err ? err.code : 0, 0));
+
+                  {
+                      id actualValue = value;
+                      VerifyOrReturn(CheckValueNull("AdminFabricIndex", actualValue));
+                  }
+
+                  testSendClusterTestSubscribe_AdministratorCommissioning_14_WaitForReport_Fulfilled = true;
+              };
+
+        NextTest();
+        return CHIP_NO_ERROR;
+    }
+
+    CHIP_ERROR TestSubscribeAdminFabricIndexAttribute_15()
+    {
+        MTRBaseDevice * device = GetDevice("alpha");
+        MTRBaseClusterAdministratorCommissioning * cluster =
+            [[MTRBaseClusterAdministratorCommissioning alloc] initWithDevice:device endpointID:@(0) queue:mCallbackQueue];
+        VerifyOrReturnError(cluster != nil, CHIP_ERROR_INCORRECT_STATE);
+
+        uint16_t minIntervalArgument = 2U;
+        uint16_t maxIntervalArgument = 50U;
+        MTRSubscribeParams * params = [[MTRSubscribeParams alloc] initWithMinInterval:@(minIntervalArgument)
+                                                                          maxInterval:@(maxIntervalArgument)];
+        params.filterByFabric = true;
+        params.replaceExistingSubscriptions = true;
+        [cluster subscribeAttributeAdminFabricIndexWithParams:params
+            subscriptionEstablished:^{
+                VerifyOrReturn(testSendClusterTestSubscribe_AdministratorCommissioning_14_WaitForReport_Fulfilled,
+                    SetCommandExitStatus(CHIP_ERROR_INCORRECT_STATE));
+                NextTest();
+            }
+            reportHandler:^(NSNumber * _Nullable value, NSError * _Nullable err) {
+                NSLog(@"Subscribe AdminFabricIndex Attribute Error: %@", err);
+
+                VerifyOrReturn(CheckValue("status", err ? err.code : 0, 0));
+                if (test_TestSubscribe_AdministratorCommissioning_AdminFabricIndex_Reported != nil) {
+                    ResponseHandler callback = test_TestSubscribe_AdministratorCommissioning_AdminFabricIndex_Reported;
+                    test_TestSubscribe_AdministratorCommissioning_AdminFabricIndex_Reported = nil;
+                    callback(value, err);
+                }
+            }];
+
+        return CHIP_NO_ERROR;
+    }
+
+    CHIP_ERROR TestOpenTheCommissioningWindow3_16()
+    {
+        MTRBaseDevice * device = GetDevice("alpha");
+        MTRBaseClusterAdministratorCommissioning * cluster =
+            [[MTRBaseClusterAdministratorCommissioning alloc] initWithDevice:device endpointID:@(0) queue:mCallbackQueue];
+        VerifyOrReturnError(cluster != nil, CHIP_ERROR_INCORRECT_STATE);
+
+        __auto_type * params = [[MTRAdministratorCommissioningClusterOpenBasicCommissioningWindowParams alloc] init];
+        params.commissioningTimeout = [NSNumber numberWithUnsignedShort:180U];
+        [cluster openBasicCommissioningWindowWithParams:params
+                                             completion:^(NSError * _Nullable err) {
+                                                 NSLog(@"Open the commissioning window 3 Error: %@", err);
+
+                                                 VerifyOrReturn(CheckValue("status", err ? err.code : 0, 0));
+
+                                                 NextTest();
+                                             }];
+
+        return CHIP_NO_ERROR;
+    }
+
+    CHIP_ERROR TestCheckForFirstAttributeReportForAdminFabricIndex_17()
+    {
+        MTRBaseDevice * device = GetDevice("alpha");
+        MTRBaseClusterAdministratorCommissioning * cluster =
+            [[MTRBaseClusterAdministratorCommissioning alloc] initWithDevice:device endpointID:@(0) queue:mCallbackQueue];
+        VerifyOrReturnError(cluster != nil, CHIP_ERROR_INCORRECT_STATE);
+
+        test_TestSubscribe_AdministratorCommissioning_AdminFabricIndex_Reported
+            = ^(NSNumber * _Nullable value, NSError * _Nullable err) {
+                  NSLog(@"Check for first attribute report for AdminFabricIndex Error: %@", err);
+
+                  VerifyOrReturn(CheckValue("status", err ? err.code : 0, 0));
+
+                  {
+                      id actualValue = value;
+                      if (ourFabricIndex == nil) {
+                          VerifyOrReturn(CheckValueNull("AdminFabricIndex", actualValue));
+                      } else {
+                          VerifyOrReturn(CheckValueNonNull("AdminFabricIndex", actualValue));
+                          VerifyOrReturn(CheckValue("AdminFabricIndex", actualValue, ourFabricIndex));
+                      }
+                  }
+
+                  NextTest();
+              };
+
+        return CHIP_NO_ERROR;
+    }
+
+    CHIP_ERROR TestCloseTheCommissioningWindow2_18()
+    {
+        MTRBaseDevice * device = GetDevice("alpha");
+        MTRBaseClusterAdministratorCommissioning * cluster =
+            [[MTRBaseClusterAdministratorCommissioning alloc] initWithDevice:device endpointID:@(0) queue:mCallbackQueue];
+        VerifyOrReturnError(cluster != nil, CHIP_ERROR_INCORRECT_STATE);
+
+        [cluster revokeCommissioningWithCompletion:^(NSError * _Nullable err) {
+            NSLog(@"Close the commissioning window 2 Error: %@", err);
+
+            VerifyOrReturn(CheckValue("status", err ? err.code : 0, 0));
+
+            NextTest();
+        }];
+
+        return CHIP_NO_ERROR;
+    }
+
+    CHIP_ERROR TestCheckForSecondAttributeReportForAdminFabricIndex_19()
+    {
+        MTRBaseDevice * device = GetDevice("alpha");
+        MTRBaseClusterAdministratorCommissioning * cluster =
+            [[MTRBaseClusterAdministratorCommissioning alloc] initWithDevice:device endpointID:@(0) queue:mCallbackQueue];
+        VerifyOrReturnError(cluster != nil, CHIP_ERROR_INCORRECT_STATE);
+
+        test_TestSubscribe_AdministratorCommissioning_AdminFabricIndex_Reported
+            = ^(NSNumber * _Nullable value, NSError * _Nullable err) {
+                  NSLog(@"Check for second attribute report for AdminFabricIndex Error: %@", err);
+
+                  VerifyOrReturn(CheckValue("status", err ? err.code : 0, 0));
+
+                  {
+                      id actualValue = value;
+                      VerifyOrReturn(CheckValueNull("AdminFabricIndex", actualValue));
+                  }
+
+                  NextTest();
+              };
+
+        return CHIP_NO_ERROR;
+    }
+};
+
 class DL_UsersAndCredentials : public TestCommandBridge {
 public:
     // NOLINTBEGIN(clang-analyzer-nullability.NullPassedToNonnull): Test constructor nullability not enforced
@@ -125555,6 +126248,7 @@
         make_unique<TestMultiAdmin>(),
         make_unique<Test_TC_DGSW_1_1>(),
         make_unique<TestSubscribe_OnOff>(),
+        make_unique<TestSubscribe_AdministratorCommissioning>(),
         make_unique<DL_UsersAndCredentials>(),
         make_unique<DL_LockUnlock>(),
         make_unique<DL_Schedules>(),