From 883b257967c9203dd33f34f3ed1ab776e0859bde Mon Sep 17 00:00:00 2001 From: Jesper Schulz-Wedde Date: Thu, 13 Aug 2026 13:24:42 +0200 Subject: [PATCH] Route pull request reviews to the owning application team The default CODEOWNERS entry pointed every path at a 123-member team, so review requests were addressed to everyone and owned by nobody. 149 of 233 ready pull requests had no review decision as a result. Generate the team rules from the routing data the BCApps triage agent already uses to classify issues and pull requests (microsoft/BCAppsTriage, plugins/triage/skills/triage/scripts/ownership/ownership-rules.js and ownership-resolver.js), which are themselves seeded from the Business Central Ownership Matrix. Deriving CODEOWNERS from that same data means the team label an item gets and the reviewer GitHub requests cannot disagree. The generated block is ordered broad to narrow, mirroring the resolver: tree defaults, Base Application areas, other W1 layer trees, W1 app exceptions, demo datasets by functional area, and documented path overrides. A team therefore appears in more than one tier; grouping by team would read better but cannot reproduce the resolver's precedence. Verified over all 46,437 tracked files: the generated block reproduces the triage resolver's path decision for 44,796 of 44,796 files it can place, and no pre-existing non-default ownership changes. 37,694 files move off the default owner. Where the final file differs from the resolver it is always a specialized rule lower in the file deliberately taking precedence (app.json, *.ps1, /build, dotnet.al, *.Entitlement.al and the Copilot and Developer Tools carve-outs inside the System Application). Two genuine disagreements between the triage rules and today's CODEOWNERS (PowerBIReports per-area folders and ServiceManagement) are recorded in a reconciliation tier that preserves current ownership rather than silently reassigning it. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: e3890caa-8e8e-4c8f-8506-5a22d422a0e0 --- CODEOWNERS | 521 ++++++++++++++++++++++++++++++---- docs/process/ReviewRouting.md | 195 +++++++++++++ 2 files changed, 658 insertions(+), 58 deletions(-) create mode 100644 docs/process/ReviewRouting.md diff --git a/CODEOWNERS b/CODEOWNERS index 6710da0fc68..b9741ed8fb4 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -5,6 +5,469 @@ # Default owners * @microsoft/dynamics-365-business-central +# --------------------------------------------------------------------------- +# Application team ownership (GENERATED - do not hand-edit) +# +# These rules are generated from the routing data the BCApps triage agent +# already uses to classify issues and pull requests: +# microsoft/BCAppsTriage +# plugins/triage/skills/triage/scripts/ownership/ownership-rules.js +# plugins/triage/skills/triage/scripts/ownership/ownership-resolver.js +# which are themselves seeded from the Business Central Ownership Matrix. +# +# They reproduce the path-based part of that resolver (its path overrides plus +# teamFromPath) exactly: every one of the 44,796 tracked files the resolver can +# place resolves to the same team here. Keeping one source means a label applied +# by the triage agent and the reviewer requested by GitHub cannot disagree. +# +# To change ownership, edit ownership-rules.js in BCAppsTriage and regenerate. +# Do not hand-edit the block below; hand edits will be lost and will silently +# diverge from issue and pull request triage. +# +# The rules are ordered broad-to-narrow because CODEOWNERS resolves +# last-match-wins, so a team can appear in more than one tier. The specialized +# cross-cutting rules further down (App Security, App Permissions, app.json, +# AL-Go and build files, Code Review Tools) still take precedence over all of +# them. +# +# See docs/process/ReviewRouting.md. +# --------------------------------------------------------------------------- + +# TIER 1 - tree defaults. +/src/Apps/W1/ @microsoft/d365-bc-integrations +/src/Layers/W1/ @microsoft/d365-bc-integrations +/src/Apps/APAC/ @microsoft/d365-bc-finance-1 +/src/Layers/APAC/ @microsoft/d365-bc-finance-1 +/src/Apps/AT/ @microsoft/d365-bc-finance-1 +/src/Layers/AT/ @microsoft/d365-bc-finance-1 +/src/Apps/AU/ @microsoft/d365-bc-finance-1 +/src/Layers/AU/ @microsoft/d365-bc-finance-1 +/src/Apps/BE/ @microsoft/d365-bc-finance-1 +/src/Layers/BE/ @microsoft/d365-bc-finance-1 +/src/Apps/CA/ @microsoft/d365-bc-finance-1 +/src/Layers/CA/ @microsoft/d365-bc-finance-1 +/src/Apps/CH/ @microsoft/d365-bc-finance-1 +/src/Layers/CH/ @microsoft/d365-bc-finance-1 +/src/Apps/CZ/ @microsoft/d365-bc-finance-1 +/src/Layers/CZ/ @microsoft/d365-bc-finance-1 +/src/Apps/DACH/ @microsoft/d365-bc-finance-1 +/src/Layers/DACH/ @microsoft/d365-bc-finance-1 +/src/Apps/DE/ @microsoft/d365-bc-finance-1 +/src/Layers/DE/ @microsoft/d365-bc-finance-1 +/src/Apps/DK/ @microsoft/d365-bc-finance-1 +/src/Layers/DK/ @microsoft/d365-bc-finance-1 +/src/Apps/ES/ @microsoft/d365-bc-finance-1 +/src/Layers/ES/ @microsoft/d365-bc-finance-1 +/src/Apps/FI/ @microsoft/d365-bc-finance-1 +/src/Layers/FI/ @microsoft/d365-bc-finance-1 +/src/Apps/FR/ @microsoft/d365-bc-finance-1 +/src/Layers/FR/ @microsoft/d365-bc-finance-1 +/src/Apps/GB/ @microsoft/d365-bc-finance-1 +/src/Layers/GB/ @microsoft/d365-bc-finance-1 +/src/Apps/IN/ @microsoft/d365-bc-finance-1 +/src/Layers/IN/ @microsoft/d365-bc-finance-1 +/src/Apps/IS/ @microsoft/d365-bc-finance-1 +/src/Layers/IS/ @microsoft/d365-bc-finance-1 +/src/Apps/IT/ @microsoft/d365-bc-finance-1 +/src/Layers/IT/ @microsoft/d365-bc-finance-1 +/src/Apps/MX/ @microsoft/d365-bc-finance-1 +/src/Layers/MX/ @microsoft/d365-bc-finance-1 +/src/Apps/NA/ @microsoft/d365-bc-finance-1 +/src/Layers/NA/ @microsoft/d365-bc-finance-1 +/src/Apps/NL/ @microsoft/d365-bc-finance-1 +/src/Layers/NL/ @microsoft/d365-bc-finance-1 +/src/Apps/NO/ @microsoft/d365-bc-finance-1 +/src/Layers/NO/ @microsoft/d365-bc-finance-1 +/src/Apps/NZ/ @microsoft/d365-bc-finance-1 +/src/Layers/NZ/ @microsoft/d365-bc-finance-1 +/src/Apps/RU/ @microsoft/d365-bc-finance-1 +/src/Layers/RU/ @microsoft/d365-bc-finance-1 +/src/Apps/SE/ @microsoft/d365-bc-finance-1 +/src/Layers/SE/ @microsoft/d365-bc-finance-1 +/src/Apps/US/ @microsoft/d365-bc-finance-1 +/src/Layers/US/ @microsoft/d365-bc-finance-1 +/src/System\ Application/ @microsoft/d365-bc-integrations +/src/Business\ Foundation/ @microsoft/d365-bc-integrations +/src/Tools/ @microsoft/d365-bc-integrations +/src/DemoTool/ @microsoft/d365-bc-integrations + +# TIER 2 - Base Application areas (W1 and every localization layer). +/src/Layers/W1/BaseApp/ @microsoft/d365-bc-integrations +/src/Layers/*/BaseApp/Assembly/ @microsoft/d365-bc-scm +/src/Layers/*/BaseApp/Bank/ @microsoft/d365-bc-finance-1 +/src/Layers/*/BaseApp/CashFlow/ @microsoft/d365-bc-finance-1 +/src/Layers/*/BaseApp/CostAccounting/ @microsoft/d365-bc-finance-1 +/src/Layers/*/BaseApp/CRM/ @microsoft/d365-bc-scm +/src/Layers/*/BaseApp/Entitlements/ @microsoft/d365-bc-integrations +/src/Layers/*/BaseApp/eServices/ @microsoft/d365-bc-integrations +/src/Layers/*/BaseApp/Finance/ @microsoft/d365-bc-finance-1 +/src/Layers/*/BaseApp/FinancialMgt/ @microsoft/d365-bc-finance-1 +/src/Layers/*/BaseApp/FixedAssets/ @microsoft/d365-bc-finance-1 +/src/Layers/*/BaseApp/Foundation/ @microsoft/d365-bc-integrations +/src/Layers/*/BaseApp/HumanResources/ @microsoft/d365-bc-scm +/src/Layers/*/BaseApp/Integration/ @microsoft/d365-bc-integrations +/src/Layers/*/BaseApp/Inventory/ @microsoft/d365-bc-scm +/src/Layers/*/BaseApp/Invoicing/ @microsoft/d365-bc-scm +/src/Layers/*/BaseApp/Manufacturing/ @microsoft/d365-bc-scm +/src/Layers/*/BaseApp/Modules/ @microsoft/d365-bc-integrations +/src/Layers/*/BaseApp/OtherCapabilities/ @microsoft/d365-bc-integrations +/src/Layers/*/BaseApp/Permissions/ @microsoft/d365-bc-integrations +/src/Layers/*/BaseApp/Pricing/ @microsoft/d365-bc-scm +/src/Layers/*/BaseApp/Projects/ @microsoft/d365-bc-finance-1 +/src/Layers/*/BaseApp/Purchases/ @microsoft/d365-bc-scm +/src/Layers/*/BaseApp/RoleCenters/ @microsoft/d365-bc-integrations +/src/Layers/*/BaseApp/Sales/ @microsoft/d365-bc-scm +/src/Layers/*/BaseApp/Service/ @microsoft/d365-bc-scm +/src/Layers/*/BaseApp/System/ @microsoft/d365-bc-integrations +/src/Layers/*/BaseApp/Utilities/ @microsoft/d365-bc-integrations +/src/Layers/*/BaseApp/Warehouse/ @microsoft/d365-bc-scm +# Finance sub-ledgers that sit physically inside an SCM area folder. +/src/Layers/*/BaseApp/Sales/Reminder/ @microsoft/d365-bc-finance-1 +/src/Layers/*/BaseApp/Sales/FinanceCharge/ @microsoft/d365-bc-finance-1 +/src/Layers/*/BaseApp/Purchases/Payables/ @microsoft/d365-bc-finance-1 + +# TIER 3 - other W1 layer trees. +/src/Layers/W1/AlCosting/ @microsoft/d365-bc-scm +/src/Layers/W1/DemoTool/ @microsoft/d365-bc-integrations +/src/Layers/W1/Tests/ @microsoft/d365-bc-integrations +# W1 test areas follow the team under test. +/src/Layers/W1/Tests/Bank/ @microsoft/d365-bc-finance-1 +/src/Layers/W1/Tests/SCM/ @microsoft/d365-bc-scm + +# TIER 4 - W1 apps that are not owned by Integration. +/src/Apps/W1/AMCBanking365Fundamentals/ @microsoft/d365-bc-finance-1 +/src/Apps/W1/APIReportsFinance/ @microsoft/d365-bc-finance-1 +/src/Apps/W1/AuditFileExport/ @microsoft/d365-bc-finance-1 +/src/Apps/W1/AutomaticAccountCodes/ @microsoft/d365-bc-finance-1 +/src/Apps/W1/BankAccRecWithAI/ @microsoft/d365-bc-finance-1 +/src/Apps/W1/BankDeposits/ @microsoft/d365-bc-finance-1 +/src/Apps/W1/CompanyHub/ @microsoft/d365-bc-finance-1 +/src/Apps/W1/CreateProductInformationWithCopilot/ @microsoft/d365-bc-scm +/src/Apps/W1/CrossEnvironmentIntercompany/ @microsoft/d365-bc-finance-1 +/src/Apps/W1/DataCorrectionFA/ @microsoft/d365-bc-finance-1 +/src/Apps/W1/EnforcedDigitalVouchers/ @microsoft/d365-bc-finance-1 +/src/Apps/W1/ESGStatisticalAccountsDemoTool/ @microsoft/d365-bc-finance-1 +/src/Apps/W1/EU3PartyTradePurchase/ @microsoft/d365-bc-finance-1 +/src/Apps/W1/ExcelReports/ @microsoft/d365-bc-finance-1 +/src/Apps/W1/ExciseTaxes/ @microsoft/d365-bc-finance-1 +/src/Apps/W1/ExpenseWithholdingTax/ @microsoft/d365-bc-finance-1 +/src/Apps/W1/FieldServiceIntegration/ @microsoft/d365-bc-scm +/src/Apps/W1/ImageAnalysis/ @microsoft/d365-bc-scm +/src/Apps/W1/INTaxEngine/ @microsoft/d365-bc-finance-1 +/src/Apps/W1/Intrastat/ @microsoft/d365-bc-finance-1 +/src/Apps/W1/LatePaymentPredictor/ @microsoft/d365-bc-finance-1 +/src/Apps/W1/Manufacturing/ @microsoft/d365-bc-scm +/src/Apps/W1/MasterDataManagement/ @microsoft/d365-bc-finance-1 +/src/Apps/W1/MSWalletPayments/ @microsoft/d365-bc-finance-1 +/src/Apps/W1/PayablesAgent/ @microsoft/d365-bc-finance-1 +/src/Apps/W1/PaymentPractices/ @microsoft/d365-bc-finance-1 +/src/Apps/W1/PayPalPaymentsStandard/ @microsoft/d365-bc-finance-1 +/src/Apps/W1/PowerBIReports/ @microsoft/d365-bc-finance-1 +/src/Apps/W1/Quality\ Management/ @microsoft/d365-bc-scm +/src/Apps/W1/ReviewGLEntries/ @microsoft/d365-bc-finance-1 +/src/Apps/W1/SAF-T/ @microsoft/d365-bc-finance-1 +/src/Apps/W1/SalesAndInventoryForecast/ @microsoft/d365-bc-scm +/src/Apps/W1/SalesLinesSuggestions/ @microsoft/d365-bc-scm +/src/Apps/W1/SalesOrderAgent/ @microsoft/d365-bc-scm +/src/Apps/W1/ServiceDeclaration/ @microsoft/d365-bc-finance-1 +/src/Apps/W1/ServiceManagement/ @microsoft/d365-bc-scm +/src/Apps/W1/SimplifiedBankStatementImport/ @microsoft/d365-bc-scm +/src/Apps/W1/StatisticalAccounts/ @microsoft/d365-bc-finance-1 +/src/Apps/W1/Subcontracting/ @microsoft/d365-bc-scm +/src/Apps/W1/Subscription\ Billing/ @microsoft/d365-bc-finance-1 +/src/Apps/W1/Sustainability/ @microsoft/d365-bc-finance-1 +/src/Apps/W1/SustainabilityContosoCoffeeDemoDataset/ @microsoft/d365-bc-finance-1 +/src/Apps/W1/SustainabilityCopilotSuggestion/ @microsoft/d365-bc-finance-1 +/src/Apps/W1/UKSendRemittanceAdvice/ @microsoft/d365-bc-finance-1 +/src/Apps/W1/VATGroupManagement/ @microsoft/d365-bc-finance-1 +/src/Apps/W1/WithholdingTax/ @microsoft/d365-bc-finance-1 +/src/Apps/W1/WorldPayPaymentsStandard/ @microsoft/d365-bc-finance-1 +# PowerBIReports hosts per-area report folders. +/src/Apps/W1/PowerBIReports/App/Inventory/ @microsoft/d365-bc-scm +/src/Apps/W1/PowerBIReports/App/Manufacturing/ @microsoft/d365-bc-scm +/src/Apps/W1/PowerBIReports/App/Sales/ @microsoft/d365-bc-scm + +# TIER 5 - demo datasets are platform tooling by default, then the +# functional DemoData area decides the owner. +/src/Apps/AT/ContosoCoffeeDemoDatasetAT/ @microsoft/d365-bc-integrations +/src/Apps/AU/ContosoCoffeeDemoDatasetAU/ @microsoft/d365-bc-integrations +/src/Apps/BE/ContosoCoffeeDemoDatasetBE/ @microsoft/d365-bc-integrations +/src/Apps/CA/ContosoCoffeeDemoDatasetCA/ @microsoft/d365-bc-integrations +/src/Apps/CH/ContosoCoffeeDemoDatasetCH/ @microsoft/d365-bc-integrations +/src/Apps/CZ/ContosoCoffeeDemoDatasetCZ/ @microsoft/d365-bc-integrations +/src/Apps/DE/ContosoCoffeeDemoDatasetDE/ @microsoft/d365-bc-integrations +/src/Apps/DK/ContosoCoffeeDemoDatasetDK/ @microsoft/d365-bc-integrations +/src/Apps/ES/ContosoCoffeeDemoDatasetES/ @microsoft/d365-bc-integrations +/src/Apps/FI/ContosoCoffeeDemoDatasetFI/ @microsoft/d365-bc-integrations +/src/Apps/FR/ContosoCoffeeDemoDatasetFR/ @microsoft/d365-bc-integrations +/src/Apps/GB/ContosoCoffeeDemoDatasetGB/ @microsoft/d365-bc-integrations +/src/Apps/IN/ContosoCoffeeDemoDatasetIN/ @microsoft/d365-bc-integrations +/src/Apps/IS/ContosoCoffeeDemoDatasetIS/ @microsoft/d365-bc-integrations +/src/Apps/IT/ContosoCoffeeDemoDatasetIT/ @microsoft/d365-bc-integrations +/src/Apps/MX/ContosoCoffeeDemoDatasetMX/ @microsoft/d365-bc-integrations +/src/Apps/NL/ContosoCoffeeDemoDatasetNL/ @microsoft/d365-bc-integrations +/src/Apps/NO/ContosoCoffeeDemoDatasetNO/ @microsoft/d365-bc-integrations +/src/Apps/NZ/ContosoCoffeeDemoDatasetNZ/ @microsoft/d365-bc-integrations +/src/Apps/SE/ContosoCoffeeDemoDatasetSE/ @microsoft/d365-bc-integrations +/src/Apps/US/ContosoCoffeeDemoDatasetUS/ @microsoft/d365-bc-integrations +/src/Apps/W1/ContosoCoffeeDemoDataset/ @microsoft/d365-bc-integrations +/src/Apps/AT/ContosoCoffeeDemoDatasetAT/app/DemoData/ @microsoft/d365-bc-integrations +/src/Apps/AT/ContosoCoffeeDemoDatasetAT/app/DemoData/Bank/ @microsoft/d365-bc-finance-1 +/src/Apps/AT/ContosoCoffeeDemoDatasetAT/app/DemoData/Common/ @microsoft/d365-bc-integrations +/src/Apps/AT/ContosoCoffeeDemoDatasetAT/app/DemoData/Finance/ @microsoft/d365-bc-finance-1 +/src/Apps/AT/ContosoCoffeeDemoDatasetAT/app/DemoData/FixedAsset/ @microsoft/d365-bc-finance-1 +/src/Apps/AT/ContosoCoffeeDemoDatasetAT/app/DemoData/Foundation/ @microsoft/d365-bc-integrations +/src/Apps/AT/ContosoCoffeeDemoDatasetAT/app/DemoData/HumanResources/ @microsoft/d365-bc-scm +/src/Apps/AT/ContosoCoffeeDemoDatasetAT/app/DemoData/Inventory/ @microsoft/d365-bc-scm +/src/Apps/AT/ContosoCoffeeDemoDatasetAT/app/DemoData/Purchases/ @microsoft/d365-bc-scm +/src/Apps/AT/ContosoCoffeeDemoDatasetAT/app/DemoData/Sale/ @microsoft/d365-bc-integrations +/src/Apps/AU/ContosoCoffeeDemoDatasetAU/app/DemoData/ @microsoft/d365-bc-integrations +/src/Apps/AU/ContosoCoffeeDemoDatasetAU/app/DemoData/Bank/ @microsoft/d365-bc-finance-1 +/src/Apps/AU/ContosoCoffeeDemoDatasetAU/app/DemoData/CRM/ @microsoft/d365-bc-scm +/src/Apps/AU/ContosoCoffeeDemoDatasetAU/app/DemoData/Common/ @microsoft/d365-bc-integrations +/src/Apps/AU/ContosoCoffeeDemoDatasetAU/app/DemoData/Finance/ @microsoft/d365-bc-finance-1 +/src/Apps/AU/ContosoCoffeeDemoDatasetAU/app/DemoData/FixedAsset/ @microsoft/d365-bc-finance-1 +/src/Apps/AU/ContosoCoffeeDemoDatasetAU/app/DemoData/Foundation/ @microsoft/d365-bc-integrations +/src/Apps/AU/ContosoCoffeeDemoDatasetAU/app/DemoData/HumanResources/ @microsoft/d365-bc-scm +/src/Apps/AU/ContosoCoffeeDemoDatasetAU/app/DemoData/Inventory/ @microsoft/d365-bc-scm +/src/Apps/AU/ContosoCoffeeDemoDatasetAU/app/DemoData/Job/ @microsoft/d365-bc-integrations +/src/Apps/AU/ContosoCoffeeDemoDatasetAU/app/DemoData/Purchases/ @microsoft/d365-bc-scm +/src/Apps/AU/ContosoCoffeeDemoDatasetAU/app/DemoData/Sales/ @microsoft/d365-bc-scm +/src/Apps/BE/ContosoCoffeeDemoDatasetBE/app/DemoData/ @microsoft/d365-bc-integrations +/src/Apps/BE/ContosoCoffeeDemoDatasetBE/app/DemoData/Bank/ @microsoft/d365-bc-finance-1 +/src/Apps/BE/ContosoCoffeeDemoDatasetBE/app/DemoData/CRM/ @microsoft/d365-bc-scm +/src/Apps/BE/ContosoCoffeeDemoDatasetBE/app/DemoData/Common/ @microsoft/d365-bc-integrations +/src/Apps/BE/ContosoCoffeeDemoDatasetBE/app/DemoData/Finance/ @microsoft/d365-bc-finance-1 +/src/Apps/BE/ContosoCoffeeDemoDatasetBE/app/DemoData/FixedAsset/ @microsoft/d365-bc-finance-1 +/src/Apps/BE/ContosoCoffeeDemoDatasetBE/app/DemoData/Foundation/ @microsoft/d365-bc-integrations +/src/Apps/BE/ContosoCoffeeDemoDatasetBE/app/DemoData/HumanResources/ @microsoft/d365-bc-scm +/src/Apps/BE/ContosoCoffeeDemoDatasetBE/app/DemoData/Inventory/ @microsoft/d365-bc-scm +/src/Apps/BE/ContosoCoffeeDemoDatasetBE/app/DemoData/Purchases/ @microsoft/d365-bc-scm +/src/Apps/BE/ContosoCoffeeDemoDatasetBE/app/DemoData/Sales/ @microsoft/d365-bc-scm +/src/Apps/BE/ContosoCoffeeDemoDatasetBE/app/DemoData/Warehousing/ @microsoft/d365-bc-scm +/src/Apps/CA/ContosoCoffeeDemoDatasetCA/app/DemoData/ @microsoft/d365-bc-integrations +/src/Apps/CA/ContosoCoffeeDemoDatasetCA/app/DemoData/Bank/ @microsoft/d365-bc-finance-1 +/src/Apps/CA/ContosoCoffeeDemoDatasetCA/app/DemoData/CRM/ @microsoft/d365-bc-scm +/src/Apps/CA/ContosoCoffeeDemoDatasetCA/app/DemoData/Finance/ @microsoft/d365-bc-finance-1 +/src/Apps/CA/ContosoCoffeeDemoDatasetCA/app/DemoData/Foundation/ @microsoft/d365-bc-integrations +/src/Apps/CA/ContosoCoffeeDemoDatasetCA/app/DemoData/HumanResources/ @microsoft/d365-bc-scm +/src/Apps/CA/ContosoCoffeeDemoDatasetCA/app/DemoData/Inventory/ @microsoft/d365-bc-scm +/src/Apps/CA/ContosoCoffeeDemoDatasetCA/app/DemoData/Purchases/ @microsoft/d365-bc-scm +/src/Apps/CA/ContosoCoffeeDemoDatasetCA/app/DemoData/Sales/ @microsoft/d365-bc-scm +/src/Apps/CA/ContosoCoffeeDemoDatasetCA/app/DemoData/eServices/ @microsoft/d365-bc-integrations +/src/Apps/CH/ContosoCoffeeDemoDatasetCH/app/DemoData/ @microsoft/d365-bc-integrations +/src/Apps/CH/ContosoCoffeeDemoDatasetCH/app/DemoData/Bank/ @microsoft/d365-bc-finance-1 +/src/Apps/CH/ContosoCoffeeDemoDatasetCH/app/DemoData/CRM/ @microsoft/d365-bc-scm +/src/Apps/CH/ContosoCoffeeDemoDatasetCH/app/DemoData/Common/ @microsoft/d365-bc-integrations +/src/Apps/CH/ContosoCoffeeDemoDatasetCH/app/DemoData/Finance/ @microsoft/d365-bc-finance-1 +/src/Apps/CH/ContosoCoffeeDemoDatasetCH/app/DemoData/FixedAsset/ @microsoft/d365-bc-finance-1 +/src/Apps/CH/ContosoCoffeeDemoDatasetCH/app/DemoData/Foundation/ @microsoft/d365-bc-integrations +/src/Apps/CH/ContosoCoffeeDemoDatasetCH/app/DemoData/HumanResources/ @microsoft/d365-bc-scm +/src/Apps/CH/ContosoCoffeeDemoDatasetCH/app/DemoData/Inventory/ @microsoft/d365-bc-scm +/src/Apps/CH/ContosoCoffeeDemoDatasetCH/app/DemoData/Purchases/ @microsoft/d365-bc-scm +/src/Apps/CH/ContosoCoffeeDemoDatasetCH/app/DemoData/Sales/ @microsoft/d365-bc-scm +/src/Apps/CZ/ContosoCoffeeDemoDatasetCZ/app/DemoData/ @microsoft/d365-bc-integrations +/src/Apps/CZ/ContosoCoffeeDemoDatasetCZ/app/DemoData/Bank/ @microsoft/d365-bc-finance-1 +/src/Apps/CZ/ContosoCoffeeDemoDatasetCZ/app/DemoData/Finance/ @microsoft/d365-bc-finance-1 +/src/Apps/CZ/ContosoCoffeeDemoDatasetCZ/app/DemoData/FixedAsset/ @microsoft/d365-bc-finance-1 +/src/Apps/CZ/ContosoCoffeeDemoDatasetCZ/app/DemoData/Foundation/ @microsoft/d365-bc-integrations +/src/Apps/CZ/ContosoCoffeeDemoDatasetCZ/app/DemoData/HumanResources/ @microsoft/d365-bc-scm +/src/Apps/CZ/ContosoCoffeeDemoDatasetCZ/app/DemoData/Inventory/ @microsoft/d365-bc-scm +/src/Apps/CZ/ContosoCoffeeDemoDatasetCZ/app/DemoData/Purchases/ @microsoft/d365-bc-scm +/src/Apps/CZ/ContosoCoffeeDemoDatasetCZ/app/DemoData/Sales/ @microsoft/d365-bc-scm +/src/Apps/DE/ContosoCoffeeDemoDatasetDE/app/DemoData/ @microsoft/d365-bc-integrations +/src/Apps/DE/ContosoCoffeeDemoDatasetDE/app/DemoData/Bank/ @microsoft/d365-bc-finance-1 +/src/Apps/DE/ContosoCoffeeDemoDatasetDE/app/DemoData/Common/ @microsoft/d365-bc-integrations +/src/Apps/DE/ContosoCoffeeDemoDatasetDE/app/DemoData/Finance/ @microsoft/d365-bc-finance-1 +/src/Apps/DE/ContosoCoffeeDemoDatasetDE/app/DemoData/FixedAsset/ @microsoft/d365-bc-finance-1 +/src/Apps/DE/ContosoCoffeeDemoDatasetDE/app/DemoData/Foundation/ @microsoft/d365-bc-integrations +/src/Apps/DE/ContosoCoffeeDemoDatasetDE/app/DemoData/HumanResources/ @microsoft/d365-bc-scm +/src/Apps/DE/ContosoCoffeeDemoDatasetDE/app/DemoData/Inventory/ @microsoft/d365-bc-scm +/src/Apps/DE/ContosoCoffeeDemoDatasetDE/app/DemoData/Purchases/ @microsoft/d365-bc-scm +/src/Apps/DE/ContosoCoffeeDemoDatasetDE/app/DemoData/Sales/ @microsoft/d365-bc-scm +/src/Apps/DK/ContosoCoffeeDemoDatasetDK/app/DemoData/ @microsoft/d365-bc-integrations +/src/Apps/DK/ContosoCoffeeDemoDatasetDK/app/DemoData/Bank/ @microsoft/d365-bc-finance-1 +/src/Apps/DK/ContosoCoffeeDemoDatasetDK/app/DemoData/Common/ @microsoft/d365-bc-integrations +/src/Apps/DK/ContosoCoffeeDemoDatasetDK/app/DemoData/Finance/ @microsoft/d365-bc-finance-1 +/src/Apps/DK/ContosoCoffeeDemoDatasetDK/app/DemoData/FixedAsset/ @microsoft/d365-bc-finance-1 +/src/Apps/DK/ContosoCoffeeDemoDatasetDK/app/DemoData/Foundation/ @microsoft/d365-bc-integrations +/src/Apps/DK/ContosoCoffeeDemoDatasetDK/app/DemoData/HumanResources/ @microsoft/d365-bc-scm +/src/Apps/DK/ContosoCoffeeDemoDatasetDK/app/DemoData/Inventory/ @microsoft/d365-bc-scm +/src/Apps/DK/ContosoCoffeeDemoDatasetDK/app/DemoData/Jobs/ @microsoft/d365-bc-finance-1 +/src/Apps/DK/ContosoCoffeeDemoDatasetDK/app/DemoData/Purchases/ @microsoft/d365-bc-scm +/src/Apps/DK/ContosoCoffeeDemoDatasetDK/app/DemoData/Sales/ @microsoft/d365-bc-scm +/src/Apps/ES/ContosoCoffeeDemoDatasetES/app/DemoData/ @microsoft/d365-bc-integrations +/src/Apps/ES/ContosoCoffeeDemoDatasetES/app/DemoData/Bank/ @microsoft/d365-bc-finance-1 +/src/Apps/ES/ContosoCoffeeDemoDatasetES/app/DemoData/CRM/ @microsoft/d365-bc-scm +/src/Apps/ES/ContosoCoffeeDemoDatasetES/app/DemoData/Common/ @microsoft/d365-bc-integrations +/src/Apps/ES/ContosoCoffeeDemoDatasetES/app/DemoData/Finance/ @microsoft/d365-bc-finance-1 +/src/Apps/ES/ContosoCoffeeDemoDatasetES/app/DemoData/FixedAsset/ @microsoft/d365-bc-finance-1 +/src/Apps/ES/ContosoCoffeeDemoDatasetES/app/DemoData/Foundation/ @microsoft/d365-bc-integrations +/src/Apps/ES/ContosoCoffeeDemoDatasetES/app/DemoData/HumanResources/ @microsoft/d365-bc-scm +/src/Apps/ES/ContosoCoffeeDemoDatasetES/app/DemoData/Inventory/ @microsoft/d365-bc-scm +/src/Apps/ES/ContosoCoffeeDemoDatasetES/app/DemoData/Purchases/ @microsoft/d365-bc-scm +/src/Apps/ES/ContosoCoffeeDemoDatasetES/app/DemoData/Sales/ @microsoft/d365-bc-scm +/src/Apps/FI/ContosoCoffeeDemoDatasetFI/app/DemoData/ @microsoft/d365-bc-integrations +/src/Apps/FI/ContosoCoffeeDemoDatasetFI/app/DemoData/Bank/ @microsoft/d365-bc-finance-1 +/src/Apps/FI/ContosoCoffeeDemoDatasetFI/app/DemoData/Common/ @microsoft/d365-bc-integrations +/src/Apps/FI/ContosoCoffeeDemoDatasetFI/app/DemoData/Finance/ @microsoft/d365-bc-finance-1 +/src/Apps/FI/ContosoCoffeeDemoDatasetFI/app/DemoData/FixedAsset/ @microsoft/d365-bc-finance-1 +/src/Apps/FI/ContosoCoffeeDemoDatasetFI/app/DemoData/Foundation/ @microsoft/d365-bc-integrations +/src/Apps/FI/ContosoCoffeeDemoDatasetFI/app/DemoData/HumanResources/ @microsoft/d365-bc-scm +/src/Apps/FI/ContosoCoffeeDemoDatasetFI/app/DemoData/Inventory/ @microsoft/d365-bc-scm +/src/Apps/FI/ContosoCoffeeDemoDatasetFI/app/DemoData/Purchases/ @microsoft/d365-bc-scm +/src/Apps/FI/ContosoCoffeeDemoDatasetFI/app/DemoData/Sales/ @microsoft/d365-bc-scm +/src/Apps/FR/ContosoCoffeeDemoDatasetFR/app/DemoData/ @microsoft/d365-bc-integrations +/src/Apps/FR/ContosoCoffeeDemoDatasetFR/app/DemoData/Bank/ @microsoft/d365-bc-finance-1 +/src/Apps/FR/ContosoCoffeeDemoDatasetFR/app/DemoData/Common/ @microsoft/d365-bc-integrations +/src/Apps/FR/ContosoCoffeeDemoDatasetFR/app/DemoData/Finance/ @microsoft/d365-bc-finance-1 +/src/Apps/FR/ContosoCoffeeDemoDatasetFR/app/DemoData/FixedAsset/ @microsoft/d365-bc-finance-1 +/src/Apps/FR/ContosoCoffeeDemoDatasetFR/app/DemoData/Foundation/ @microsoft/d365-bc-integrations +/src/Apps/FR/ContosoCoffeeDemoDatasetFR/app/DemoData/HumanResources/ @microsoft/d365-bc-scm +/src/Apps/FR/ContosoCoffeeDemoDatasetFR/app/DemoData/Inventory/ @microsoft/d365-bc-scm +/src/Apps/FR/ContosoCoffeeDemoDatasetFR/app/DemoData/Purchases/ @microsoft/d365-bc-scm +/src/Apps/FR/ContosoCoffeeDemoDatasetFR/app/DemoData/Sales/ @microsoft/d365-bc-scm +/src/Apps/FR/ContosoCoffeeDemoDatasetFR/app/DemoData/Warehousing/ @microsoft/d365-bc-scm +/src/Apps/GB/ContosoCoffeeDemoDatasetGB/app/DemoData/ @microsoft/d365-bc-integrations +/src/Apps/GB/ContosoCoffeeDemoDatasetGB/app/DemoData/Bank/ @microsoft/d365-bc-finance-1 +/src/Apps/GB/ContosoCoffeeDemoDatasetGB/app/DemoData/Common/ @microsoft/d365-bc-integrations +/src/Apps/GB/ContosoCoffeeDemoDatasetGB/app/DemoData/Finance/ @microsoft/d365-bc-finance-1 +/src/Apps/GB/ContosoCoffeeDemoDatasetGB/app/DemoData/FixedAsset/ @microsoft/d365-bc-finance-1 +/src/Apps/GB/ContosoCoffeeDemoDatasetGB/app/DemoData/Foundation/ @microsoft/d365-bc-integrations +/src/Apps/GB/ContosoCoffeeDemoDatasetGB/app/DemoData/HumanResources/ @microsoft/d365-bc-scm +/src/Apps/GB/ContosoCoffeeDemoDatasetGB/app/DemoData/Inventory/ @microsoft/d365-bc-scm +/src/Apps/GB/ContosoCoffeeDemoDatasetGB/app/DemoData/Purchases/ @microsoft/d365-bc-scm +/src/Apps/GB/ContosoCoffeeDemoDatasetGB/app/DemoData/Sales/ @microsoft/d365-bc-scm +/src/Apps/GB/ContosoCoffeeDemoDatasetGB/app/DemoData/eService/ @microsoft/d365-bc-integrations +/src/Apps/IN/ContosoCoffeeDemoDatasetIN/app/DemoData/ @microsoft/d365-bc-integrations +/src/Apps/IN/ContosoCoffeeDemoDatasetIN/app/DemoData/Bank/ @microsoft/d365-bc-finance-1 +/src/Apps/IN/ContosoCoffeeDemoDatasetIN/app/DemoData/CRM/ @microsoft/d365-bc-scm +/src/Apps/IN/ContosoCoffeeDemoDatasetIN/app/DemoData/Finance/ @microsoft/d365-bc-finance-1 +/src/Apps/IN/ContosoCoffeeDemoDatasetIN/app/DemoData/FixedAsset/ @microsoft/d365-bc-finance-1 +/src/Apps/IN/ContosoCoffeeDemoDatasetIN/app/DemoData/Foundation/ @microsoft/d365-bc-integrations +/src/Apps/IN/ContosoCoffeeDemoDatasetIN/app/DemoData/Inventory/ @microsoft/d365-bc-scm +/src/Apps/IN/ContosoCoffeeDemoDatasetIN/app/DemoData/Purchases/ @microsoft/d365-bc-scm +/src/Apps/IN/ContosoCoffeeDemoDatasetIN/app/DemoData/Sales/ @microsoft/d365-bc-scm +/src/Apps/IS/ContosoCoffeeDemoDatasetIS/app/DemoData/ @microsoft/d365-bc-integrations +/src/Apps/IS/ContosoCoffeeDemoDatasetIS/app/DemoData/Bank/ @microsoft/d365-bc-finance-1 +/src/Apps/IS/ContosoCoffeeDemoDatasetIS/app/DemoData/Common/ @microsoft/d365-bc-integrations +/src/Apps/IS/ContosoCoffeeDemoDatasetIS/app/DemoData/Finance/ @microsoft/d365-bc-finance-1 +/src/Apps/IS/ContosoCoffeeDemoDatasetIS/app/DemoData/FixedAsset/ @microsoft/d365-bc-finance-1 +/src/Apps/IS/ContosoCoffeeDemoDatasetIS/app/DemoData/Foundation/ @microsoft/d365-bc-integrations +/src/Apps/IS/ContosoCoffeeDemoDatasetIS/app/DemoData/HumanResources/ @microsoft/d365-bc-scm +/src/Apps/IS/ContosoCoffeeDemoDatasetIS/app/DemoData/Inventory/ @microsoft/d365-bc-scm +/src/Apps/IS/ContosoCoffeeDemoDatasetIS/app/DemoData/Purchases/ @microsoft/d365-bc-scm +/src/Apps/IS/ContosoCoffeeDemoDatasetIS/app/DemoData/Sale/ @microsoft/d365-bc-integrations +/src/Apps/IT/ContosoCoffeeDemoDatasetIT/app/DemoData/ @microsoft/d365-bc-integrations +/src/Apps/IT/ContosoCoffeeDemoDatasetIT/app/DemoData/Analytics/ @microsoft/d365-bc-integrations +/src/Apps/IT/ContosoCoffeeDemoDatasetIT/app/DemoData/Bank/ @microsoft/d365-bc-finance-1 +/src/Apps/IT/ContosoCoffeeDemoDatasetIT/app/DemoData/CRM/ @microsoft/d365-bc-scm +/src/Apps/IT/ContosoCoffeeDemoDatasetIT/app/DemoData/Common/ @microsoft/d365-bc-integrations +/src/Apps/IT/ContosoCoffeeDemoDatasetIT/app/DemoData/Finance/ @microsoft/d365-bc-finance-1 +/src/Apps/IT/ContosoCoffeeDemoDatasetIT/app/DemoData/Foundation/ @microsoft/d365-bc-integrations +/src/Apps/IT/ContosoCoffeeDemoDatasetIT/app/DemoData/Inventory/ @microsoft/d365-bc-scm +/src/Apps/IT/ContosoCoffeeDemoDatasetIT/app/DemoData/Purchases/ @microsoft/d365-bc-scm +/src/Apps/IT/ContosoCoffeeDemoDatasetIT/app/DemoData/Sales/ @microsoft/d365-bc-scm +/src/Apps/MX/ContosoCoffeeDemoDatasetMX/app/DemoData/ @microsoft/d365-bc-integrations +/src/Apps/MX/ContosoCoffeeDemoDatasetMX/app/DemoData/Bank/ @microsoft/d365-bc-finance-1 +/src/Apps/MX/ContosoCoffeeDemoDatasetMX/app/DemoData/Common/ @microsoft/d365-bc-integrations +/src/Apps/MX/ContosoCoffeeDemoDatasetMX/app/DemoData/Finance/ @microsoft/d365-bc-finance-1 +/src/Apps/MX/ContosoCoffeeDemoDatasetMX/app/DemoData/Foundation/ @microsoft/d365-bc-integrations +/src/Apps/MX/ContosoCoffeeDemoDatasetMX/app/DemoData/Inventory/ @microsoft/d365-bc-scm +/src/Apps/MX/ContosoCoffeeDemoDatasetMX/app/DemoData/Purchases/ @microsoft/d365-bc-scm +/src/Apps/MX/ContosoCoffeeDemoDatasetMX/app/DemoData/Sales/ @microsoft/d365-bc-scm +/src/Apps/NL/ContosoCoffeeDemoDatasetNL/app/DemoData/ @microsoft/d365-bc-integrations +/src/Apps/NL/ContosoCoffeeDemoDatasetNL/app/DemoData/Bank/ @microsoft/d365-bc-finance-1 +/src/Apps/NL/ContosoCoffeeDemoDatasetNL/app/DemoData/CRM/ @microsoft/d365-bc-scm +/src/Apps/NL/ContosoCoffeeDemoDatasetNL/app/DemoData/Common/ @microsoft/d365-bc-integrations +/src/Apps/NL/ContosoCoffeeDemoDatasetNL/app/DemoData/Finance/ @microsoft/d365-bc-finance-1 +/src/Apps/NL/ContosoCoffeeDemoDatasetNL/app/DemoData/FixedAsset/ @microsoft/d365-bc-finance-1 +/src/Apps/NL/ContosoCoffeeDemoDatasetNL/app/DemoData/Foundation/ @microsoft/d365-bc-integrations +/src/Apps/NL/ContosoCoffeeDemoDatasetNL/app/DemoData/HumanResources/ @microsoft/d365-bc-scm +/src/Apps/NL/ContosoCoffeeDemoDatasetNL/app/DemoData/Inventory/ @microsoft/d365-bc-scm +/src/Apps/NL/ContosoCoffeeDemoDatasetNL/app/DemoData/Purchases/ @microsoft/d365-bc-scm +/src/Apps/NL/ContosoCoffeeDemoDatasetNL/app/DemoData/Sales/ @microsoft/d365-bc-scm +/src/Apps/NL/ContosoCoffeeDemoDatasetNL/app/DemoData/Warehousing/ @microsoft/d365-bc-scm +/src/Apps/NO/ContosoCoffeeDemoDatasetNO/app/DemoData/ @microsoft/d365-bc-integrations +/src/Apps/NO/ContosoCoffeeDemoDatasetNO/app/DemoData/Bank/ @microsoft/d365-bc-finance-1 +/src/Apps/NO/ContosoCoffeeDemoDatasetNO/app/DemoData/Common/ @microsoft/d365-bc-integrations +/src/Apps/NO/ContosoCoffeeDemoDatasetNO/app/DemoData/Finance/ @microsoft/d365-bc-finance-1 +/src/Apps/NO/ContosoCoffeeDemoDatasetNO/app/DemoData/FixedAsset/ @microsoft/d365-bc-finance-1 +/src/Apps/NO/ContosoCoffeeDemoDatasetNO/app/DemoData/Foundation/ @microsoft/d365-bc-integrations +/src/Apps/NO/ContosoCoffeeDemoDatasetNO/app/DemoData/HumanResources/ @microsoft/d365-bc-scm +/src/Apps/NO/ContosoCoffeeDemoDatasetNO/app/DemoData/Inventory/ @microsoft/d365-bc-scm +/src/Apps/NO/ContosoCoffeeDemoDatasetNO/app/DemoData/Purchases/ @microsoft/d365-bc-scm +/src/Apps/NO/ContosoCoffeeDemoDatasetNO/app/DemoData/Sales/ @microsoft/d365-bc-scm +/src/Apps/NZ/ContosoCoffeeDemoDatasetNZ/app/DemoData/ @microsoft/d365-bc-integrations +/src/Apps/NZ/ContosoCoffeeDemoDatasetNZ/app/DemoData/Bank/ @microsoft/d365-bc-finance-1 +/src/Apps/NZ/ContosoCoffeeDemoDatasetNZ/app/DemoData/CRM/ @microsoft/d365-bc-scm +/src/Apps/NZ/ContosoCoffeeDemoDatasetNZ/app/DemoData/Common/ @microsoft/d365-bc-integrations +/src/Apps/NZ/ContosoCoffeeDemoDatasetNZ/app/DemoData/Finance/ @microsoft/d365-bc-finance-1 +/src/Apps/NZ/ContosoCoffeeDemoDatasetNZ/app/DemoData/Foundation/ @microsoft/d365-bc-integrations +/src/Apps/NZ/ContosoCoffeeDemoDatasetNZ/app/DemoData/HumanResources/ @microsoft/d365-bc-scm +/src/Apps/NZ/ContosoCoffeeDemoDatasetNZ/app/DemoData/Inventory/ @microsoft/d365-bc-scm +/src/Apps/NZ/ContosoCoffeeDemoDatasetNZ/app/DemoData/Purchases/ @microsoft/d365-bc-scm +/src/Apps/NZ/ContosoCoffeeDemoDatasetNZ/app/DemoData/Sales/ @microsoft/d365-bc-scm +/src/Apps/SE/ContosoCoffeeDemoDatasetSE/app/DemoData/ @microsoft/d365-bc-integrations +/src/Apps/SE/ContosoCoffeeDemoDatasetSE/app/DemoData/Bank/ @microsoft/d365-bc-finance-1 +/src/Apps/SE/ContosoCoffeeDemoDatasetSE/app/DemoData/Common/ @microsoft/d365-bc-integrations +/src/Apps/SE/ContosoCoffeeDemoDatasetSE/app/DemoData/Finance/ @microsoft/d365-bc-finance-1 +/src/Apps/SE/ContosoCoffeeDemoDatasetSE/app/DemoData/FixedAsset/ @microsoft/d365-bc-finance-1 +/src/Apps/SE/ContosoCoffeeDemoDatasetSE/app/DemoData/Foundation/ @microsoft/d365-bc-integrations +/src/Apps/SE/ContosoCoffeeDemoDatasetSE/app/DemoData/HumanResources/ @microsoft/d365-bc-scm +/src/Apps/SE/ContosoCoffeeDemoDatasetSE/app/DemoData/Inventory/ @microsoft/d365-bc-scm +/src/Apps/SE/ContosoCoffeeDemoDatasetSE/app/DemoData/Purchases/ @microsoft/d365-bc-scm +/src/Apps/SE/ContosoCoffeeDemoDatasetSE/app/DemoData/Sales/ @microsoft/d365-bc-scm +/src/Apps/US/ContosoCoffeeDemoDatasetUS/app/DemoData/ @microsoft/d365-bc-integrations +/src/Apps/US/ContosoCoffeeDemoDatasetUS/app/DemoData/Bank/ @microsoft/d365-bc-finance-1 +/src/Apps/US/ContosoCoffeeDemoDatasetUS/app/DemoData/Finance/ @microsoft/d365-bc-finance-1 +/src/Apps/US/ContosoCoffeeDemoDatasetUS/app/DemoData/FixedAsset/ @microsoft/d365-bc-finance-1 +/src/Apps/US/ContosoCoffeeDemoDatasetUS/app/DemoData/Foundation/ @microsoft/d365-bc-integrations +/src/Apps/US/ContosoCoffeeDemoDatasetUS/app/DemoData/HumanResources/ @microsoft/d365-bc-scm +/src/Apps/US/ContosoCoffeeDemoDatasetUS/app/DemoData/Inventory/ @microsoft/d365-bc-scm +/src/Apps/US/ContosoCoffeeDemoDatasetUS/app/DemoData/Purchases/ @microsoft/d365-bc-scm +/src/Apps/US/ContosoCoffeeDemoDatasetUS/app/DemoData/Sales/ @microsoft/d365-bc-scm +/src/Apps/US/ContosoCoffeeDemoDatasetUS/app/DemoData/eServices/ @microsoft/d365-bc-integrations +/src/Apps/W1/ContosoCoffeeDemoDataset/app/DemoData/ @microsoft/d365-bc-integrations +/src/Apps/W1/ContosoCoffeeDemoDataset/app/DemoData/Analytics/ @microsoft/d365-bc-integrations +/src/Apps/W1/ContosoCoffeeDemoDataset/app/DemoData/Bank/ @microsoft/d365-bc-finance-1 +/src/Apps/W1/ContosoCoffeeDemoDataset/app/DemoData/CRM/ @microsoft/d365-bc-scm +/src/Apps/W1/ContosoCoffeeDemoDataset/app/DemoData/Common/ @microsoft/d365-bc-integrations +/src/Apps/W1/ContosoCoffeeDemoDataset/app/DemoData/Finance/ @microsoft/d365-bc-finance-1 +/src/Apps/W1/ContosoCoffeeDemoDataset/app/DemoData/FixedAsset/ @microsoft/d365-bc-finance-1 +/src/Apps/W1/ContosoCoffeeDemoDataset/app/DemoData/Foundation/ @microsoft/d365-bc-integrations +/src/Apps/W1/ContosoCoffeeDemoDataset/app/DemoData/HumanResources/ @microsoft/d365-bc-scm +/src/Apps/W1/ContosoCoffeeDemoDataset/app/DemoData/Inventory/ @microsoft/d365-bc-scm +/src/Apps/W1/ContosoCoffeeDemoDataset/app/DemoData/Jobs/ @microsoft/d365-bc-finance-1 +/src/Apps/W1/ContosoCoffeeDemoDataset/app/DemoData/Manufacturing/ @microsoft/d365-bc-scm +/src/Apps/W1/ContosoCoffeeDemoDataset/app/DemoData/Purchases/ @microsoft/d365-bc-scm +/src/Apps/W1/ContosoCoffeeDemoDataset/app/DemoData/Sales/ @microsoft/d365-bc-scm +/src/Apps/W1/ContosoCoffeeDemoDataset/app/DemoData/Service/ @microsoft/d365-bc-scm +/src/Apps/W1/ContosoCoffeeDemoDataset/app/DemoData/Warehousing/ @microsoft/d365-bc-scm +/src/Apps/W1/ContosoCoffeeDemoDataset/app/DemoData/eServices/ @microsoft/d365-bc-integrations +/src/Apps/W1/SustainabilityContosoCoffeeDemoDataset/app/DemoData/ @microsoft/d365-bc-finance-1 +/src/Apps/W1/SustainabilityContosoCoffeeDemoDataset/app/DemoData/Sustainability/ @microsoft/d365-bc-finance-1 + +# TIER 6 - documented overrides. +/src/Apps/IT/ServiceDeclarationIT/ @microsoft/d365-bc-scm +# Localization apps that are not Finance (recognised connector variants). +/src/Apps/BE/ShopifyBE/ @microsoft/d365-bc-integrations +# Non-src trees the resolver still maps. +/tools/ @microsoft/d365-bc-integrations +/src/Layers/.config/ @microsoft/d365-bc-finance-1 + +# TIER 7 - reconciliation pending (NOT generated). +# The triage agent routes these to SCM, today's CODEOWNERS routes them to +# Finance. Current ownership is preserved here so this change takes nothing away +# from a team. Settle it in ownership-rules.js in BCAppsTriage, then regenerate +# and delete this tier. +# PowerBIReports per-area report folders: triage resolves App/ to the +# area owner (e.g. App/Sales -> SCM); CODEOWNERS has owned the whole app as +# Finance since #9752. +# ServiceManagement: appFolderRules says SCM; CODEOWNERS says Finance. +/src/Apps/W1/PowerBIReports @microsoft/d365-bc-finance-1 +/src/Apps/W1/ServiceManagement @microsoft/d365-bc-finance-1 + # App Rulesets /src/rulesets/ @microsoft/d365-bc-app-rulesets @@ -18,64 +481,6 @@ /src/System\ Application/App/Extension\ Management @microsoft/dynamics-smb-developertools /src/System\ Application/Test/Extension\ Management @microsoft/dynamics-smb-developertools -# App Finance -/src/Apps/W1/PowerBIReports @microsoft/d365-bc-finance-1 -/src/Apps/APAC/EDocumentFormats @microsoft/d365-bc-finance-1 -/src/Apps/CH/SwissQRBill @microsoft/d365-bc-finance-1 -/src/Apps/CZ/FixedAssetLocalization @microsoft/d365-bc-finance-1 -/src/Apps/DE/EDocumentDE @microsoft/d365-bc-finance-1 -/src/Apps/DE/Elster @microsoft/d365-bc-finance-1 -/src/Apps/DK/ElectronicVATDeclarationDK @microsoft/d365-bc-finance-1 -/src/Apps/DK/EnforcedDigitalVouchersDK @microsoft/d365-bc-finance-1 -/src/Apps/DK/FIK @microsoft/d365-bc-finance-1 -/src/Apps/DK/NemhandelNotification @microsoft/d365-bc-finance-1 -/src/Apps/DK/SAFTModificationDK @microsoft/d365-bc-finance-1 -/src/Apps/DK/VATReportsDK @microsoft/d365-bc-finance-1 -/src/Apps/ES/EDocumentFormats @microsoft/d365-bc-finance-1 -/src/Apps/FR/FAReportsFR @microsoft/d365-bc-finance-1 -/src/Apps/FR/FECAuditFile @microsoft/d365-bc-finance-1 -/src/Apps/FR/PaymentManagementFR @microsoft/d365-bc-finance-1 -/src/Apps/FR/ServiceDeclarationFR @microsoft/d365-bc-finance-1 -/src/Apps/GB/GovTalk @microsoft/d365-bc-finance-1 -/src/Apps/GB/IdealPostcodes @microsoft/d365-bc-finance-1 -/src/Apps/GB/PostingDateCheckOnPosting @microsoft/d365-bc-finance-1 -/src/Apps/GB/ReportsGB @microsoft/d365-bc-finance-1 -/src/Apps/GB/ReverseChargeVAT @microsoft/d365-bc-finance-1 -/src/Apps/GB/UKMakingTaxDigital @microsoft/d365-bc-finance-1 -/src/Apps/GB/UKPostcodeGetAddressIO @microsoft/d365-bc-finance-1 -/src/Apps/GB/VATReporting @microsoft/d365-bc-finance-1 -/src/Apps/NA/Ceridian @microsoft/d365-bc-finance-1 -/src/Apps/NA/EnvestnetYodleeBankFeeds @microsoft/d365-bc-finance-1 -/src/Apps/NA/ExtendedBankDepositNA @microsoft/d365-bc-finance-1 -/src/Apps/NA/MX_DIOT @microsoft/d365-bc-finance-1 -/src/Apps/NA/Onprem\ Permissions\ NA @microsoft/d365-bc-finance-1 -/src/Apps/NL/NLDigitalTaxDeclaration @microsoft/d365-bc-finance-1 -/src/Apps/NO/ElectronicVATSubmission @microsoft/d365-bc-finance-1 -/src/Apps/NO/NorwegianSAFT @microsoft/d365-bc-finance-1 -/src/Apps/SE/SIE @microsoft/d365-bc-finance-1 -/src/Apps/US/IRS1096 @microsoft/d365-bc-finance-1 -/src/Apps/US/IRSForms @microsoft/d365-bc-finance-1 -/src/Apps/W1/AMCBanking365Fundamentals @microsoft/d365-bc-finance-1 -/src/Apps/W1/AuditFileExport @microsoft/d365-bc-finance-1 -/src/Apps/W1/BankAccRecWithAI @microsoft/d365-bc-finance-1 -/src/Apps/W1/BankDeposits @microsoft/d365-bc-finance-1 -/src/Apps/W1/CompanyHub @microsoft/d365-bc-finance-1 -/src/Apps/W1/CrossEnvironmentIntercompany @microsoft/d365-bc-finance-1 -/src/Apps/W1/EnforcedDigitalVouchers @microsoft/d365-bc-finance-1 -/src/Apps/W1/ExciseTaxes @microsoft/d365-bc-finance-1 -/src/Apps/W1/MasterDataManagement @microsoft/d365-bc-finance-1 -/src/Apps/W1/PayPalPaymentsStandard @microsoft/d365-bc-finance-1 -/src/Apps/W1/ReviewGLEntries @microsoft/d365-bc-finance-1 -/src/Apps/W1/SAF-T @microsoft/d365-bc-finance-1 -/src/Apps/W1/ServiceDeclaration @microsoft/d365-bc-finance-1 -/src/Apps/W1/ServiceManagement @microsoft/d365-bc-finance-1 -/src/Apps/W1/StatisticalAccounts @microsoft/d365-bc-finance-1 -/src/Apps/W1/Subscription\ Billing @microsoft/d365-bc-finance-1 -/src/Apps/W1/Sustainability @microsoft/d365-bc-finance-1 -/src/Apps/W1/SustainabilityCopilotSuggestion @microsoft/d365-bc-finance-1 -/src/Apps/W1/VATGroupManagement @microsoft/d365-bc-finance-1 -/src/Apps/W1/WithholdingTax @microsoft/d365-bc-finance-1 - # App Security dotnet.al @microsoft/d365-bc-app-security diff --git a/docs/process/ReviewRouting.md b/docs/process/ReviewRouting.md new file mode 100644 index 00000000000..61f45a2571d --- /dev/null +++ b/docs/process/ReviewRouting.md @@ -0,0 +1,195 @@ +# Review routing: how a pull request finds its reviewer + +This document explains the two mechanisms that decide who is asked to review a pull request, why +they must agree, and what still needs to change. + +--- + +## There are two mechanisms, not one + +This surprises people, and the difference matters: + +| | `CODEOWNERS` | Ruleset `required_reviewers` | +|---|---|---| +| Lives in | `/CODEOWNERS` in the repo | repository rulesets (admin UI/API) | +| Effect | **requests** review from the owner when a PR opens | **requires** approval before merge | +| Drives | `review-requested:@me` — the personal queue | the merge gate | +| Changed by | a pull request | a repository administrator | + +`CODEOWNERS` is what makes a review show up in a developer's inbox. The ruleset is what stops a merge. +They are independent, and today they disagree in places. + +Note that `microsoft-production-ruleset` sets `require_code_owner_review: true`, so entries in +`CODEOWNERS` are not merely advisory — a code owner's approval is required. + +--- + +## What was wrong + +`CODEOWNERS` opened with a single default: + +``` +* @microsoft/dynamics-365-business-central +``` + +That team has **123 members**. Every pull request therefore requested review from 123 people, which +is the textbook setup for the bystander effect: a request addressed to everyone is owned by nobody. + +The measurable consequence: **149 of 233 ready pull requests had no review decision at all**. GitHub +itself could not say who owed the review, so no filter, query or dashboard could either. + +The `Official Branches` ruleset has the same shape — a `*` pattern requiring one approval from the +same 123-member team. + +--- + +## What changed in `CODEOWNERS` + +The team rules are now **generated** from the routing data the BCApps triage agent already uses to +classify issues and pull requests: + +- `microsoft/BCAppsTriage` → `plugins/triage/skills/triage/scripts/ownership/ownership-rules.js` +- `microsoft/BCAppsTriage` → `plugins/triage/skills/triage/scripts/ownership/ownership-resolver.js` + +which are in turn seeded from the Business Central Ownership Matrix. That agent already decides which +team owns an issue or pull request; deriving `CODEOWNERS` from the same data means **the team label +on an item and the reviewer GitHub requests cannot disagree**. + +Previously this file was going to be hand-derived from the ownership matrix separately. That was a +mistake: a second, hand-maintained copy of the same mapping drifts from the first one immediately. +It also got several areas wrong — most of `src/Layers/*` and the country localization trees were not +routed at all, and `ExpenseAgent`, `Intrastat`, `Projects` and `Invoicing` were assigned to the wrong +team. + +### Structure + +The generated block is ordered **broad to narrow**, because `CODEOWNERS` resolves last-match-wins and +the resolver it mirrors is itself layered: + +| Tier | Contains | +|---|---| +| 1 | Tree defaults — W1 apps and layers to Integration, every country tree to Finance | +| 2 | Base Application areas, for W1 and every localization layer, plus the Finance sub-ledgers that sit inside SCM area folders (`Sales/Reminder`, `Purchases/Payables`) | +| 3 | Other W1 layer trees, including per-area test ownership | +| 4 | W1 apps that are not Integration, plus the per-area `PowerBIReports` folders | +| 5 | Demo datasets, which follow the functional `DemoData/` folder rather than the app | +| 6 | Documented path overrides (for example the Italian Service Declaration) | +| 7 | Reconciliation pending — see below | + +A consequence worth calling out: **a team appears in more than one tier**. Grouping every rule for a +team together would be easier to read, but it cannot reproduce the resolver's precedence, so +correctness wins. + +### Verification + +Two properties are checked mechanically over all 46,437 tracked files: + +| Check | Result | +|---|---| +| Generated block reproduces the triage resolver's path decision | **44,796 of 44,796 files (100%)** | +| Pre-existing non-default ownership changed | **0 files** | +| Files moved off the 123-member default owner | **37,694** | + +Where the final file differs from the triage resolver, it is always because a specialized rule lower +in the file deliberately takes precedence — `app.json` to the app team, `*.ps1` and `/build` to +Engineering Systems, `dotnet.al` to App Security, `*.Entitlement.al` to Integration, and the Copilot +and Developer Tools carve-outs inside the System Application. That is the intended +"Integration owns the System Application, with sub-sections owned by others" shape. + +### How closely this matches the labels the agent actually applies + +Reproducing the resolver is not the same as matching the team label a pull request ends up with, so +that was measured separately over 425 labelled pull requests: + +| Outcome | PRs | Share | +|---|---|---| +| Single-team PR, `CODEOWNERS` matches the label | 312 | 73.4% | +| Multi-team PR, labelled team is the dominant owner | 68 | 16.0% | +| Multi-team PR, labelled team owns a minority of files | 13 | 3.1% | +| `CODEOWNERS` never requests the labelled team | 25 | 5.9% | +| No team owner at all | 7 | 1.6% | + +**`CODEOWNERS` requests the labelled team on 92.5% of pull requests.** + +Exact one-to-one agreement is neither expected nor desirable, for two structural reasons: + +- **They answer different questions.** The agent picks a *single* team per item. `CODEOWNERS` + requests *every* owner of *every* touched file, so a pull request spanning two teams correctly + gets two reviewers. That accounts for most of the difference. +- **The agent reads file content.** `resolveTeamForFile` tries overrides, then object id, then + namespace, and only then path. `CODEOWNERS` can only ever see the path, so the two must diverge + wherever a file's namespace or object id disagrees with its folder. + +### Two disagreements left unresolved on purpose + +The triage rules and today's `CODEOWNERS` genuinely disagree in two places. Taking ownership away +from a team is not something this change should do silently, so current ownership is preserved in +tier 7 and the disagreement is recorded instead: + +- **`PowerBIReports`** — the triage agent resolves its per-area report folders to the area owner + (`App/Sales` to SCM); `CODEOWNERS` has owned the whole app as Finance since #9752. +- **`ServiceManagement`** — `appFolderRules` says SCM; `CODEOWNERS` says Finance. + +Both should be settled in `ownership-rules.js`, after which tier 7 disappears on the next +regeneration. + +### Findings for whoever maintains `ownership-rules.js` + +Three things surfaced while checking the 25 disagreements. None of them block this change, but each +is a genuine inconsistency in the upstream rules rather than something `CODEOWNERS` should paper +over: + +1. **Intrastat** is forced to SCM by an override keyed on the *namespace* + `Microsoft.Inventory.Intrastat` and object id 4810 — explicitly so that "PRs and issues agree" — + but `appFolderRules.Intrastat` says `Finance`. A path-only consumer cannot see the namespace, so + `CODEOWNERS` routes Intrastat to Finance. A path rule would close the gap. +2. **`BaseApp/Projects`** — `baseAppAreaRules.Projects` says `Finance`, while + `subAreaToTeam['Projects']` and the ownership matrix both say SCM. The agent resolves SCM via + object id (Job, table 167). The two data sections contradict each other. +3. **Country E-Document labels look stale.** Seven of the 25 disagreements are country E-Document + apps labelled `Integration`, while `ownership-rules.js` carries an override routing them to + Finance whose comment notes it "deliberately supersedes the earlier #9172 decision". Those labels + predate the override and would benefit from a re-run of classification. + +### What this costs the teams + +Because code owner review is required, these entries make each team a required approver for its +paths. From currently open, non-draft pull requests that have a team owner — 187 of them, of which +**53 touch more than one team** and therefore need approval from each: + +| Team | Members | Open PRs | Per member | +|---|---|---|---| +| Finance | 8 | 91 | 11.4 | +| SCM | 9 | 73 | 8.1 | +| Integration | 10 | 90 | 9.0 | + +Integration changes the most: it previously owned almost nothing in `CODEOWNERS` and now owns the +System Application, Business Foundation, the migration and connector apps, and every unlisted W1 app. + +### Regenerating +Edit `ownership-rules.js` in `BCAppsTriage` and regenerate. The generator reads `ownership-rules.js` +and `ownership-resolver.js` directly, so it lives alongside them in `BCAppsTriage` rather than here. +Do not hand-edit the generated block. +Hand edits are lost on the next regeneration and silently diverge from issue and pull request triage. +## What still needs to change (requires an administrator) +`CODEOWNERS` alone does not finish the job. The `Official Branches` ruleset still contains: + +``` +file_patterns: ["*"] -> dynamics-365-business-central (123 members), minimum_approvals: 1 +``` + +While that rule stands, every pull request still requires an approval from the 123-member group, so +the merge gate remains anonymous even though the *request* is now correctly routed. + +**Recommendation:** replace the `*` catch-all with the same three team patterns used in `CODEOWNERS`, +keeping `*` only as a fallback for paths no team claims. This must be done by someone with repository +administration rights, and should follow — not precede — the `CODEOWNERS` change, so that routing is +proven before the merge gate is tightened. + +--- + +## Why routing has to be fixed first + +Until a review request lands on a named team, `reviewDecision` stays empty — and an empty +`reviewDecision` is exactly the state that no query, filter or report can triage. Any later work on +making the backlog visible depends on this being right first.