{
  "nbformat": 4,
  "nbformat_minor": 5,
  "metadata": {
    "kernelspec": {
      "display_name": "Python 3",
      "language": "python",
      "name": "python3"
    },
    "language_info": {
      "name": "python",
      "version": "3.13.0"
    },
    "blog_metadata": {
      "topic": "What Local Inferencing Means for Microsoft 365 Copilot Governance",
      "slug": "what-local-inferencing-means-for-microsoft-365-copilot-gover",
      "generated_by": "LinkedIn Post Generator + Azure OpenAI",
      "generated_at": "2026-09-22T21:56:11.791Z"
    }
  },
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "# What Local Inferencing Means for Microsoft 365 Copilot Governance\n",
        "\n",
        "This notebook turns the blog post into hands-on validation exercises using Python. The core idea is that local inferencing is not a governance exemption: it shifts more control responsibility to the endpoint while identity, authorization, DLP, retention, audit, and evidence still determine whether Microsoft 365 Copilot is actually governed."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {},
      "source": [
        "%pip install pandas networkx matplotlib"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "metadata": {},
      "source": [
        "import json\n",
        "from datetime import datetime, timezone\n",
        "from pathlib import Path\n",
        "\n",
        "import pandas as pd\n",
        "import networkx as nx\n",
        "import matplotlib.pyplot as plt"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Visualize the governance boundary shift\n",
        "\n",
        "This example recreates the blog's cloud-vs-local inference flow as a graph. It helps validate the central claim: cloud paths concentrate more evidence in centralized services, while local paths make endpoint posture and local telemetry part of the governance boundary."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {},
      "source": [
        "nodes = [\n",
        "    \"User prompt in Microsoft 365 app\",\n",
        "    \"Inference location\",\n",
        "    \"Copilot service applies tenant controls\",\n",
        "    \"Model runs on managed endpoint\",\n",
        "    \"Endpoint posture becomes a governance control\",\n",
        "    \"Purview / audit / DLP evidence\",\n",
        "    \"Device compliance / app control / local logging\",\n",
        "    \"Governance review\",\n",
        "]\n",
        "\n",
        "edges = [\n",
        "    (\"User prompt in Microsoft 365 app\", \"Inference location\"),\n",
        "    (\"Inference location\", \"Copilot service applies tenant controls\"),\n",
        "    (\"Inference location\", \"Model runs on managed endpoint\"),\n",
        "    (\"Model runs on managed endpoint\", \"Endpoint posture becomes a governance control\"),\n",
        "    (\"Copilot service applies tenant controls\", \"Purview / audit / DLP evidence\"),\n",
        "    (\"Model runs on managed endpoint\", \"Device compliance / app control / local logging\"),\n",
        "    (\"Purview / audit / DLP evidence\", \"Governance review\"),\n",
        "    (\"Device compliance / app control / local logging\", \"Governance review\"),\n",
        "]\n",
        "\n",
        "G = nx.DiGraph()\n",
        "G.add_nodes_from(nodes)\n",
        "G.add_edges_from(edges)\n",
        "\n",
        "pos = {\n",
        "    \"User prompt in Microsoft 365 app\": (0, 0),\n",
        "    \"Inference location\": (1.5, 0),\n",
        "    \"Copilot service applies tenant controls\": (3, 1),\n",
        "    \"Model runs on managed endpoint\": (3, -1),\n",
        "    \"Endpoint posture becomes a governance control\": (5, -1),\n",
        "    \"Purview / audit / DLP evidence\": (5, 1),\n",
        "    \"Device compliance / app control / local logging\": (5, -2),\n",
        "    \"Governance review\": (7, 0),\n",
        "}\n",
        "\n",
        "plt.figure(figsize=(14, 6))\n",
        "nx.draw(\n",
        "    G,\n",
        "    pos,\n",
        "    with_labels=True,\n",
        "    node_size=3500,\n",
        "    node_color=\"#DCEEFF\",\n",
        "    font_size=9,\n",
        "    arrows=True,\n",
        "    arrowsize=20,\n",
        ")\n",
        "plt.title(\"Governance Boundary Shift: Cloud vs Local Inference\")\n",
        "plt.axis(\"off\")\n",
        "plt.show()"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Model the evidence collection sequence\n",
        "\n",
        "The blog emphasizes that governance depends on evidence, not labels like \"local\" or \"cloud.\" This sequence-style validation shows how a reviewer, script, tenant, and managed endpoint contribute to a governance evidence package."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {},
      "source": [
        "sequence_steps = [\n",
        "    (\"Governance Reviewer\", \"Evidence Script\", \"Run evidence collection\"),\n",
        "    (\"Evidence Script\", \"Microsoft 365 Tenant\", \"Query Copilot-related settings\"),\n",
        "    (\"Evidence Script\", \"Microsoft 365 Tenant\", \"Record control assumptions\"),\n",
        "    (\"Evidence Script\", \"Managed Endpoint\", \"Capture local inference prerequisites\"),\n",
        "    (\"Microsoft 365 Tenant\", \"Evidence Script\", \"Config snapshots\"),\n",
        "    (\"Managed Endpoint\", \"Evidence Script\", \"Endpoint posture facts\"),\n",
        "    (\"Evidence Script\", \"Governance Reviewer\", \"Governance evidence package\"),\n",
        "]\n",
        "\n",
        "seq_df = pd.DataFrame(sequence_steps, columns=[\"from\", \"to\", \"message\"])\n",
        "seq_df.index = seq_df.index + 1\n",
        "seq_df"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Build a compact governance evidence record\n",
        "\n",
        "This Python version mirrors the PowerShell example from the post. It creates a timestamped, reviewable evidence object that captures assumptions and baseline controls before rollout."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {},
      "source": [
        "evidence = {\n",
        "    \"CollectedAtUtc\": datetime.now(timezone.utc).strftime(\"%Y-%m-%dT%H:%M:%SZ\"),\n",
        "    \"TenantId\": \"contoso.onmicrosoft.com\",\n",
        "    \"ReviewScope\": \"Microsoft 365 Copilot governance\",\n",
        "    \"Assumptions\": [\n",
        "        \"Local inferencing may shift control reliance to endpoint posture\",\n",
        "        \"Connector exposure must be reviewed before broad enablement\",\n",
        "        \"Audit evidence must exist for both cloud and endpoint paths\",\n",
        "    ],\n",
        "    \"Controls\": {\n",
        "        \"CopilotEnabled\": True,\n",
        "        \"PurviewAuditEnabled\": True,\n",
        "        \"DlpPoliciesReviewed\": True,\n",
        "        \"SensitivityLabelsRequired\": True,\n",
        "        \"ManagedDevicesRequired\": True,\n",
        "    },\n",
        "}\n",
        "\n",
        "print(json.dumps(evidence, indent=2))"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Export a governance control inventory\n",
        "\n",
        "This example converts the blog's inventory idea into a CSV artifact. The goal is to make partial, missing, or blocked controls visible before broad enablement."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {},
      "source": [
        "inventory = pd.DataFrame([\n",
        "    {\"Control\": \"CopilotLicenseAssigned\", \"State\": \"Partial\", \"Evidence\": \"Group-based licensing\"},\n",
        "    {\"Control\": \"PurviewAudit\", \"State\": \"Enabled\", \"Evidence\": \"Unified audit log retained\"},\n",
        "    {\"Control\": \"SensitivityLabels\", \"State\": \"Required\", \"Evidence\": \"Default labels for SharePoint/Teams\"},\n",
        "    {\"Control\": \"ConnectorReview\", \"State\": \"InProgress\", \"Evidence\": \"Top 10 connectors assessed\"},\n",
        "    {\"Control\": \"ManagedEndpoint\", \"State\": \"Required\", \"Evidence\": \"Compliant + encrypted devices only\"},\n",
        "])\n",
        "\n",
        "path = Path(\"copilot-governance-inventory.csv\")\n",
        "inventory.to_csv(path, index=False)\n",
        "\n",
        "artifact_info = {\n",
        "    \"FullName\": str(path.resolve()),\n",
        "    \"Length\": path.stat().st_size,\n",
        "    \"LastWriteTimeUtc\": datetime.fromtimestamp(path.stat().st_mtime, tz=timezone.utc).strftime(\"%Y-%m-%dT%H:%M:%SZ\"),\n",
        "}\n",
        "\n",
        "print(inventory)\n",
        "print(\"\\nArtifact:\")\n",
        "print(json.dumps(artifact_info, indent=2))"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Evaluate endpoint readiness for local inferencing\n",
        "\n",
        "The blog argues that a compliant device alone is not enough. This check validates whether endpoint posture is strong enough for local inferencing scenarios and highlights gaps such as missing application control."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {},
      "source": [
        "device = {\n",
        "    \"DeviceName\": \"LAB-ENDPOINT-01\",\n",
        "    \"Encrypted\": True,\n",
        "    \"EdrHealthy\": True,\n",
        "    \"Compliant\": True,\n",
        "    \"AppControlEnforced\": False,\n",
        "    \"LocalAiRuntimeApproved\": True,\n",
        "}\n",
        "\n",
        "ready = (\n",
        "    device[\"Encrypted\"]\n",
        "    and device[\"EdrHealthy\"]\n",
        "    and device[\"Compliant\"]\n",
        "    and device[\"LocalAiRuntimeApproved\"]\n",
        ")\n",
        "\n",
        "result = {\n",
        "    \"DeviceName\": device[\"DeviceName\"],\n",
        "    \"LocalInferenceReady\": ready,\n",
        "    \"Gap\": \"None\" if device[\"AppControlEnforced\"] else \"Enable application control before broad rollout\",\n",
        "}\n",
        "\n",
        "print(json.dumps(result, indent=2))"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Score a single AI use case for governance risk\n",
        "\n",
        "This is the blog's lightweight worksheet for turning abstract debate into a concrete decision. It scores a use case across sensitivity, endpoint posture, connector exposure, residency, and audit evidence needs."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {},
      "source": [
        "weights = {\n",
        "    \"data_sensitivity\": 5,\n",
        "    \"endpoint_posture\": 4,\n",
        "    \"connector_exposure\": 4,\n",
        "    \"residency_requirement\": 3,\n",
        "    \"audit_evidence_need\": 2,\n",
        "}\n",
        "\n",
        "use_case = {\n",
        "    \"name\": \"Draft board summary from SharePoint and Teams\",\n",
        "    \"data_sensitivity\": 5,\n",
        "    \"endpoint_posture\": 2,\n",
        "    \"connector_exposure\": 4,\n",
        "    \"residency_requirement\": 3,\n",
        "    \"audit_evidence_need\": 5,\n",
        "}\n",
        "\n",
        "score = sum(use_case[k] * weights[k] for k in weights)\n",
        "tier = \"High\" if score >= 55 else \"Moderate\" if score >= 35 else \"Low\"\n",
        "\n",
        "print({\"use_case\": use_case[\"name\"], \"risk_score\": score, \"tier\": tier})"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Build a worksheet for multiple use cases\n",
        "\n",
        "This expands the scoring model into a simple decision worksheet. It demonstrates how different business scenarios should lead to different governance actions instead of being treated as one policy bucket."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {},
      "source": [
        "use_cases = [\n",
        "    {\"name\": \"Sales recap\", \"data_sensitivity\": 2, \"endpoint_posture\": 4, \"connector_exposure\": 2, \"residency_requirement\": 1, \"audit_evidence_need\": 2},\n",
        "    {\"name\": \"HR policy assistant\", \"data_sensitivity\": 5, \"endpoint_posture\": 2, \"connector_exposure\": 3, \"residency_requirement\": 4, \"audit_evidence_need\": 5},\n",
        "]\n",
        "\n",
        "rows = []\n",
        "for item in use_cases:\n",
        "    score = (\n",
        "        item[\"data_sensitivity\"] * 5\n",
        "        + item[\"endpoint_posture\"] * 4\n",
        "        + item[\"connector_exposure\"] * 4\n",
        "        + item[\"residency_requirement\"] * 3\n",
        "        + item[\"audit_evidence_need\"] * 2\n",
        "    )\n",
        "    action = \"Allow local inference pilot\" if score < 35 else \"Require extra controls\" if score < 55 else \"Keep cloud-only with approvals\"\n",
        "    rows.append({**item, \"score\": score, \"action\": action})\n",
        "\n",
        "worksheet = pd.DataFrame(rows)\n",
        "worksheet"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Map governance controls to evidence expectations by inference path\n",
        "\n",
        "This example highlights the fragmented-enforcement problem described in the post. Cloud and local inference paths require different evidence, and neither path removes the need for governance controls."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {},
      "source": [
        "paths = {\n",
        "    \"cloud\": [\"Purview audit\", \"DLP policy match\", \"service-side access review\"],\n",
        "    \"local\": [\"device compliance\", \"EDR health\", \"approved runtime inventory\", \"local log collection\"],\n",
        "}\n",
        "\n",
        "for path, controls in paths.items():\n",
        "    print(f\"{path.upper()} INFERENCE\")\n",
        "    for control in controls:\n",
        "        print(f\" - {control}\")\n",
        "    print()"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Validate a no-go decision tree\n",
        "\n",
        "The blog recommends blocking local-capable scenarios when sensitivity is high, endpoints are unmanaged, connector paths are unclear, or evidence requirements cannot be met. This Python decision function operationalizes that review motion."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {},
      "source": [
        "def local_inference_decision(sensitive_or_regulated, managed_compliant_endpoint, connector_reviewed):\n",
        "    if sensitive_or_regulated:\n",
        "        return \"Prefer cloud inference with stronger centralized evidence\"\n",
        "    if not managed_compliant_endpoint:\n",
        "        return \"Block local inference\"\n",
        "    if not connector_reviewed:\n",
        "        return \"Review connectors and permissions\"\n",
        "    return \"Approve pilot with audit evidence plan\"\n",
        "\n",
        "scenarios = [\n",
        "    {\"scenario\": \"Board materials\", \"sensitive_or_regulated\": True, \"managed_compliant_endpoint\": True, \"connector_reviewed\": True},\n",
        "    {\"scenario\": \"General productivity on unmanaged laptop\", \"sensitive_or_regulated\": False, \"managed_compliant_endpoint\": False, \"connector_reviewed\": True},\n",
        "    {\"scenario\": \"Low-risk managed pilot with unreviewed connectors\", \"sensitive_or_regulated\": False, \"managed_compliant_endpoint\": True, \"connector_reviewed\": False},\n",
        "    {\"scenario\": \"Low-risk managed pilot with reviewed connectors\", \"sensitive_or_regulated\": False, \"managed_compliant_endpoint\": True, \"connector_reviewed\": True},\n",
        "]\n",
        "\n",
        "results = []\n",
        "for s in scenarios:\n",
        "    decision = local_inference_decision(\n",
        "        s[\"sensitive_or_regulated\"],\n",
        "        s[\"managed_compliant_endpoint\"],\n",
        "        s[\"connector_reviewed\"],\n",
        "    )\n",
        "    results.append({**s, \"decision\": decision})\n",
        "\n",
        "pd.DataFrame(results)"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Rate your environment on policy-path provability\n",
        "\n",
        "The post ends with a practical question: can you prove the policy path for an AI action across identity, endpoint, connector, and output? This quick self-assessment turns that into a repeatable scoring prompt."
      ]
    },
    {
      "cell_type": "code",
      "metadata": {},
      "source": [
        "assessment = {\n",
        "    \"identity\": 4,\n",
        "    \"endpoint\": 3,\n",
        "    \"connector\": 2,\n",
        "    \"output\": 3,\n",
        "}\n",
        "\n",
        "average_score = sum(assessment.values()) / len(assessment)\n",
        "rounded = round(average_score, 1)\n",
        "\n",
        "if average_score >= 4.5:\n",
        "    maturity = \"Strong\"\n",
        "elif average_score >= 3.5:\n",
        "    maturity = \"Good but with notable gaps\"\n",
        "elif average_score >= 2.5:\n",
        "    maturity = \"Moderate risk\"\n",
        "else:\n",
        "    maturity = \"Weak governance posture\"\n",
        "\n",
        "print({\n",
        "    \"scores\": assessment,\n",
        "    \"average\": rounded,\n",
        "    \"maturity\": maturity,\n",
        "    \"question\": \"Can you prove the policy path for an AI action across identity, endpoint, connector, and output?\",\n",
        "})"
      ],
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Next Steps\n",
        "\n",
        "Local inferencing can reduce some data movement, but it does not replace identity, device trust, DLP, retention, eDiscovery, or audit evidence. Use the worksheets in this notebook to classify use cases, test endpoint readiness, document assumptions, and block rollout where controls are partial or fragmented.\n",
        "\n",
        "Next, adapt the sample evidence record and inventory to your tenant, define no-go cases for unmanaged or weakly controlled endpoints, and pilot on high-risk workflows where permissions, evidence, and endpoint posture actually matter."
      ]
    }
  ]
}